通用过载解决方案
我有以下场景:
class Foo { }
class Foo<T> : Foo { }
然后有两个方法
void DoStuff(Foo foo)
{
DoStuffImpl(foo);
}
void DoStuffImpl(Foo foo)
{
Console.WriteLine("A");
}
void DoStuffImpl<T>(Foo<T> foo)
{
Console.WriteLine("B");
}
void Main()
{
DoStuff(new Foo<int>()); // prints A
}
(注意,代码是在浏览器中编写的,但描述了我面临的情况)
如何让它调用通用方法并打印 B?
这是否可以在不反思的情况下完成?我对如何通过反射来完成它有一些想法,但我正在寻找一种更干净的解决方案(如果存在)。
注意:我无法使 DoStuff
泛型,因为它将与 WCF 一起使用,并且不允许开放泛型类型。
I have the following scenario:
class Foo { }
class Foo<T> : Foo { }
And then two methods
void DoStuff(Foo foo)
{
DoStuffImpl(foo);
}
void DoStuffImpl(Foo foo)
{
Console.WriteLine("A");
}
void DoStuffImpl<T>(Foo<T> foo)
{
Console.WriteLine("B");
}
void Main()
{
DoStuff(new Foo<int>()); // prints A
}
(note, the code was written in the browser, but describes the situation I'm facing)
How can I get it to call the generic method, and print B?
Can this be done at all without reflection? I have some ideas on how it could be done with reflection, but I'm looking for a cleaner solution if one exists.
Note: I can't make DoStuff
generic because this will be used with WCF and open generic types are not allowed.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(2)
(我假设您已经了解为什么会发生这种情况。如果没有,请阅读我的重载解决文章如果仍然不清楚,请告诉我。)
如果您使用 C# 4,您可以使用动态类型:
请注意,这不仅仅是一个动态参数 - 这个想法是通过限制
foo
属于Foo
类型或子类,我们总是有一个有效的DoStuffImpl
来调用...它是只是最好的方法将在执行时确定,而不是编译时。如果您陷入 C# 4 之前的版本,您可以使用双重调度来实现:
然后:
(I assume you already understand why this is happening. If not, read my overload resolution article and let me know if it's still unclear.)
If you're using C# 4 you could use dynamic typing:
Note how this doesn't just have a dynamic parameter - the idea is that by restricting
foo
to be of typeFoo
or a subclass, we'll always have a validDoStuffImpl
to call... it's just that the best method will be determined at execution time, not compile time.If you're stuck in pre-C# 4, you could potentially do it with double dispatch:
Then:
重载解析在编译时执行。当“DoStuff”被编译时,它已经决定要调用哪个版本的DoStuffImpl,并且它是根据编译时可用的信息而不是运行时可用的信息来决定的。
C# 中有四种方法分派:
静态分派在编译时选择静态方法。在运行时,将调用所选择的方法。
实例分派在编译时选择实例方法。在运行时,调用所选方法。 (这是在非虚拟实例方法和使用“base”调用的虚拟方法上使用的分派形式。)
虚拟分派在编译时选择实例方法。在运行时,调用对象的运行时类型上该方法的最重写版本。
动态调度在编译时不执行任何操作 (*)。在运行时编译器会再次启动并在运行时进行编译时分析,并生成全新的代码,如果您一开始就在编译时正确编写了该代码,则会生成新的代码。听起来确实很贵;幸运的是,结果被缓存,这样在第二次调用时,您就不会再次获得分析和代码生成的所有成本。
动态调度仅适用于 C# 4 或任何版本的 VB。
(*) 这并不完全正确;在某些情况下,即使方法的参数是动态的,编译器也可以在编译时进行分析。细节很复杂。
Overload resolution is performed at compile time. When "DoStuff" is compiled, it has already decided which version of DoStuffImpl to call, and it decides that based on the information available at compile time, not the information available at runtime.
There are four kinds of method dispatching in C#:
static dispatching chooses a static method at compile time. At runtime, the chosen method is called.
instance dispatching chooses an instance method at compile time. At runtime, the chosen method is called. (This is the form of dispatching used on non-virtual instance methods and on virtual methods called with "base.")
virtual dispatching chooses an instance method at compile time. At runtime, the most overridding version of that method on the runtime type of the object is called.
dynamic dispatching does nothing at compile time (*). At runtime the compiler starts up again and does the compile-time analysis at runtime, and generates fresh new code that is what would have been written had you gotten it right at compile time in the first place. This is every bit as expensive as it sounds; fortunately the result is cached so that on the second call, you don't get all the cost of analysis and codegen again.
Dynamic dispatching is only available in C# 4, or any version of VB.
(*) This is not quite true; there are some circumstances in which the compiler can do analysis at compile time even if the arguments to the method are dynamic. The details are complicated.