C #. إضافة تعدد الأشكال عن رمز تراث
-
03-07-2019 - |
سؤال
وافترض لدينا دروس الإرث، التي لا يمكن تعديل:
class Foo
{
public void Calculate(int a) { }
}
class Bar
{
public void Compute(int a) {}
}
وأريد أن أكتب مساعد مع هذا التوقيع:
void Calc(object obj, int a);
لاحظ أن الحجة الأولى هي من نوع 'الكائن'. يجب أن يكون رمز اختبار بعض من هذا القبيل:
ExampleX.Calc((object)new Foo(), 0);
ExampleX.Calc((object)new Bar(), 0);
والسؤال هو، ما التنفيذ يمكنك أن تتخيل بالإضافة إلى هذه:
// Using If/then
class Example1
{
public static void Calc(object obj, int a)
{
if (obj is Foo)
((Foo)obj).Calculate(a);
else if (obj is Bar)
((Bar)obj).Compute(a);
}
}
// Using reflection
class Example2
{
private static Dictionary<Type, MethodInfo> _methods = new Dictionary<Type, MethodInfo>();
static Example2()
{
_methods.Add(typeof(Foo), typeof(Foo).GetMethod("Calculate"));
_methods.Add(typeof(Bar), typeof(Bar).GetMethod("Compute"));
}
public static void Calc(object obj, int a)
{
_methods[obj.GetType()].Invoke(obj, new object[] { a });
}
}
// Using delegates
class Example3
{
private delegate void CalcDelegate(object obj, int a);
private static Dictionary<Type, CalcDelegate> _methods = new Dictionary<Type, CalcDelegate>();
static Example3()
{
_methods.Add(typeof(Foo), (o, a) => ((Foo)o).Calculate(a));
_methods.Add(typeof(Bar), (o, a) => ((Bar)o).Compute(a));
}
public static void Calc(object obj, int a)
{
_methods[obj.GetType()](obj, a);
}
}
// Using Reflection + overloaded methods
class Example4
{
private delegate void CalcDelegate(object obj, int a);
public static void Calc(object obj, int a)
{
Type[] types = new Type[] {
obj.GetType(), typeof(int)
};
typeof(Example4).GetMethod("Calc", types).Invoke(null, new object[] { obj, a });
}
public static void Calc(Foo obj, int a)
{
obj.Calculate(a);
}
public static void Calc(Bar obj, int a)
{
obj.Compute(a);
}
}
وشكرا!
المحلول
وأود أن تذهب على سبيل المثال 1، لأن لها أبسط واحد، والأكثر وضوحا.
وأود أن استخدام مثال 2 فقط إذا كنت تتوقع أنواع جديدة من الكائنات مع واحدة من هاتين الطريقتين، ومثال 3 فقط إذا كان لديك الكثير (عشرات إن لم يكن مئات) من الأشياء ويبدأ الأداء كونها قضية.
وتحرير: أو تمديد الأساليب إذا كنت صافي 3
نصائح أخرى
استخدم أساليب الإرشاد لإضافة أساسا وظيفة جديدة إلى نوع القائمة.
وهذه هي الطريقة التي أود أن أكتب الحل. فهو يقلل من خطر التعرض لمشاكل نوع السلامة في رمز ويقضي على التفكير.
class Example2
{
private static Dictionary<Type, Action<object,int>> _methods = new Dictionary<Type, Action<object,int>>();
static Example2()
{
Add<Foo>( (f,a) => f.Calculate(a) );
Add<Bar>( (b,a) => b.Compute(a) );
}
public static void Calc<TSource>(TSource source, int a)
{
_methods[typeof(TSource)](source,a);
}
public static void Add<TSource>(Action<TSource,int> del)
{
Action<object,int> wrapper = (x,i) => { del((TSource)x, i); };
_methods[typeof(TSource)] = wrapper;
}
}
لا تنتمي إلى StackOverflow