我有一组我没写过的课程,而且它们只读。 让我们说,例如,那些类是以下类:
public class Base { }
public class B : Base { }
public class C : B { }
public class D : Base { }
我想在所有这些类上添加方法Foo()
,我正在使用扩展方法:
public static class Extensions {
public static void Foo(this Base obj) {
dynamic dynobj = obj;
try {
dynobj.Foo();
}
catch (RuntimeBinderException ex) {
Console.WriteLine(ex.Message);
}
}
public static void Foo(this B b) {
Console.WriteLine("Foo in B");
}
public static void Foo(this C c) {
Console.WriteLine("Foo in C");
}
}
正如您所看到的,我正在尝试使用关键字dynamic
,期望它知道我的对象的真实类型并调用其Foo()
方法。但是...... dynobj.Foo()
总是失败。
static void Main(string[] args) {
List<Base> list = new List<Base>();
list.Add(new B());
list.Add(new C());
list.Add(new D());
list.ForEach(x => x.Foo());
}
我知道我可以使用适配器模式,但我的课程确实太多了。
使用dynamic
执行此操作是个好主意吗?是否有可能使这项工作?
谢谢。
答案 0 :(得分:5)
这是因为Foo永远不会被添加为方法。扩展方法仍然只是静态类中的静态方法,实际上并不直接与所讨论的类相关联。它们不像混合物(红宝石)。编译器只是将对象上的调用转换为静态方法。
与致电相同:Extensions.Foo(thing)
我最好的建议是创建一个查找表(Dictionary),您可以注册不同版本的Foo。
这样的东西(未经测试),也许?
public static class Extensions {
private static Dictionary<Type, Action<Base>> callFoo = new Dictionary<Type, Action<Base>>
{
{typeof(B), b => (b as B).Foo()},
{typeof(C), b => (b as C).Foo()}
};
public static void Foo(this Base obj) {
try {
callFoo[typeof(obj)](obj);
}
catch (RuntimeBinderException ex) {
Console.WriteLine(ex.Message);
}
}
public static void Foo(this B b) {
Console.WriteLine("Foo in B");
}
public static void Foo(this C c) {
Console.WriteLine("Foo in C");
}
}
答案 1 :(得分:1)
我解决了我的问题,只保留Base {Foo()
扩展方法,并使其他扩展方法采用常规静态方法,将B
,C
或D
作为参数。
public static void Foo(this Base obj) {
try {
Foo_(obj as dynamic);
}
catch (RuntimeBinderException ex) {
Console.WriteLine(ex.Message);
}
}
private static void Foo_(B b) {
Console.WriteLine("Foo in B");
b.ListOfBs.ForEach(x => x.Foo());
}
private static void Foo_(C c) {
Console.WriteLine("C.Name = {0}", c.Name);
}
答案 2 :(得分:0)
还有另一个原因,你的解决方案不是一个好主意 - Base
没有被定义为抽象类,所以有可能有人可以实例化它,即使你的技术有效,也会遇到如果他们试图调用其Foo()
方法,则堆栈溢出。
如果你拿走Base的Foo()方法,Foo()是不是按预期调用的(调用C类的Foo()扩展方法的实例最终会达到B的Foo()扩展方法)?
如果它不起作用,您可以始终保持老式并创建包装类。