3

可能重复:
泛型方法重载的问题

这是一个简单的代码:

static class Example  
{  
    static int DoIt(object o) { return 0; }    
    class A { }
    static int DoIt(A a) { return 1; }
    static int CallDoIt<X>(X x) { return DoIt(x); }
    static void Main()
    {
        var a = new A();
        System.Console.WriteLine(DoIt(a));      // returns 1 (as desired)
        System.Console.WriteLine(CallDoIt(a));  // returns 0
    }
}

结果看起来很奇怪:直接调用的函数 DoIt() 返回的值与从另一个函数调用它的情况不同。这是 C# 中的预期行为吗?如果是,如何实现所需的行为(最好没有反射)?

4

6 回答 6

2

This is the expected behaviour, the knowledge of what type X is does not extend into the CallDoIt function. The overload of DoIt called from CallDoIt is determined statically based on the type of the argument x. Since X can be anything, the best (and only) candidate is DoIt(object).

You can get around this behaviour by delaying the dispatch to DoIt until runtime using dynamic:

static int CallDoIt<X>(X x) { return DoIt((dynamic)x); }

The other alternative is to provide a more specific version of CallDoIt:

static int CallDoIt(A a) { return DoIt(a); }
于 2013-01-27T20:32:15.947 回答
1

DoIt(x)方法内部的方法调用CallDoIt<X>(X x)必须适用于任何X类型,因此 C# 编译器选择使用DoIt(object o)重载。如果您将类型限制为从这样X的类型派生:A

static int CallDoIt<X>(X x) where X : A { return DoIt(x); }

然后 C# 编译器会知道它可以选择DoIt(A a)重载,因为Xtype 总是派生自 type A。这也回答了您关于如何实现所需行为的第二个问题。

于 2013-01-27T20:54:53.097 回答
0

Yes, that is the expected behaviour. A generic method is compiled once for all possible arguments. During that single compilation, DoIt(x) cannot be resolved to DoIt(A), so it is DoIt(object), and that is what it will always be.

You can dynamically check the object type, or better yet, have .NET Framework do so for you:

static int CallDoIt(object x) { return DoIt((dynamic)x); }

Note that there is no benefit here to making CallDoIt generic: it would do exactly the same as this version. That means that CallDoIt((object)a) calls DoIt(A), not DoIt(object).

于 2013-01-27T20:33:57.483 回答
0

为 CallDoIt 添加另一个重载:

static int CallDoIt(A x) { return DoIt(x); }

这将使事情顺利进行。

于 2013-01-27T20:34:50.657 回答
0

重载解析发生在编译时(如果不需要动态解析)并且X(类型参数)的最具体类型是object.

于 2013-01-27T20:36:57.553 回答
0

选择调用方法的决定将在编译时解决。C# 编译器不知道 X 是什么类型,并选择了带有 DoIt(object o) 的方法。

于 2013-01-27T20:40:49.513 回答