假设我们有遗留类,无法修改:
class Foo
{
public void Calculate(int a) { }
}
class Bar
{
public void Compute(int a) {}
}
我想写一个带有这种签名的帮手:
void Calc(object obj, int a);
注意,第一个参数是'object'类型。测试代码应该是这样的:
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);
}
}
谢谢!
答案 0 :(得分:3)
使用扩展方法实质上将新函数添加到现有类型。
答案 1 :(得分:2)
这就是我编写解决方案的方法。它降低了代码中类型安全问题的风险,并消除了反射。
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;
}
}
答案 2 :(得分:1)
你总是可以使用adapter pattern来实现不可更改的遗留对象,而不会破坏任何依赖于其功能的对象,同时仍然能够为对象实现自己的(新)功能。
答案 3 :(得分:0)
我会举例1,因为它是最简单的一个,也是最明显的。
我只使用示例2,如果您期望使用这两种方法之一的新类型的对象,并且仅当您有很多(几十甚至几百)个对象并且性能开始成为问题时,我将使用示例3。
编辑:或扩展方法,如果你是.Net 3