通用重载决议
我有以下情况:
class Foo { } class Foo : Foo { }
然后是两种方法
void DoStuff(Foo foo) { DoStuffImpl(foo); } void DoStuffImpl(Foo foo) { Console.WriteLine("A"); } void DoStuffImpl(Foo foo) { Console.WriteLine("B"); } void Main() { DoStuff(new Foo()); // prints A }
(注意,代码是在浏览器中编写的,但描述了我面临的情况)
如何让它调用generics方法,然后打印B?
这可以在没有反思的情况下完成吗? 关于如何用reflection完成,我有一些想法,但我正在寻找一个更清洁的解决方案,如果存在的话。
注意:我不能使DoStuff
generics,因为它将与WCF一起使用,并且不允许打开generics类型。
(我假设你已经明白为什么会发生这种情况。如果没有,请阅读我的重载决议文章并告诉我它是否仍然不清楚。)
如果您使用的是C#4,则可以使用动态类型:
void DoStuff(Foo foo) { dynamic d = foo; DoStuffImpl(d); }
注意这不仅仅有一个动态参数 – 想法是通过将foo
限制为Foo
类型或子类,我们总是有一个有效的DoStuffImpl
来调用…它只是确定最好的方法在执行时,不是编译时间。
如果你被困在C#4之前,你可以通过双重调度来实现:
class Foo { public virtual void CallStuffImpl(FooImplType x) { x.DoStuffImpl(this); } } class Foo : Foo { public override void CallStuffImpl(FooImplType x) { // Looks like it's redundant, but isn't! "this" is // known to be Foo rather than Foo x.DoStuffImpl(this); } }
然后:
void DoStuff(Foo foo) { foo.CallStuffImpl(this); // Let it dispatch appropriately }
过载分辨率在编译时执行。 编译“DoStuff”时,它已经决定调用哪个版本的DoStuffImpl,它根据编译时可用的信息决定,而不是运行时可用的信息。
C#中有四种方法调度:
-
静态调度在编译时选择静态方法。 在运行时,调用所选方法。
-
实例调度在编译时选择实例方法。 在运行时,调用所选方法。 (这是在非虚拟实例方法和使用“base”调用的虚拟方法上使用的调度forms。)
-
虚拟调度在编译时选择实例方法。 在运行时,将调用该对象的运行时类型上该方法的最重写版本 。
-
动态调度在编译时不执行任何操作(*)。 在运行时,编译器再次启动并在运行时进行编译时分析,并生成新的新代码,如果您在编译时首先将其编写完成,那么这些代码将会被编写。 这听起来有点贵; 幸运的是,结果被缓存,因此在第二次调用时,您不会再次获得所有分析和代码的成本。
动态调度仅适用于C#4或任何版本的VB。
(*)这不完全正确; 在某些情况下,即使方法的参数是动态的,编译器也可以在编译时进行分析。 细节很复杂。