多态性不适用于C#中泛型类的调用

Gut*_*tti 10 c# generics polymorphism interface class

看起来在以下情况下多态性无法正常工作我有以下定义:

interface BaseInterface{}
interface NewInterface:BaseInterface{}
class NewClass:NewInterface{}

class GenericClass<T> where T:BaseInterface
{
    public string WhoIAm(T anObject)
    {
        return TestPolymorphism.CheckInterface(anObject);
    }
}

class ImplementedClass:GenericClass<NewInterface>{}

class TestPolymorphism
{
    public static string CheckInterface(BaseInterface anInterface)
    {
        return "BaseInterface";
    }

    public static string CheckInterface(NewInterface anInterface)
    {
        return "NewInterface";
    }
}
Run Code Online (Sandbox Code Playgroud)

然后当我打电话:

NewClass nc = new NewClass();
ImplementedClass impClass = new ImplementedClass();
Console.WriteLine("The result is " + impClass.WhoIAm(nc));
Run Code Online (Sandbox Code Playgroud)

我有"结果是BaseInterface"

我希望有"结果是NewInterface"作为nc实现BaseClass和NewClass
什么是获得"NewClass"的最佳方法?

谢谢

Jam*_*are 17

请记住通用方法,非虚方法调用仍然在通用本身的编译时解析,而不是在通用实现的编译时解析.

这样:

class GenericClass<T> where T:BaseInterface
{
    public string WhoIAm(T anObject)
    {
        return TestPolymorphism.CheckInterface(anObject);
    }
}
Run Code Online (Sandbox Code Playgroud)

将解决过载,BaseInterface因为这是你所限制的,无论T实际是什么类型.

C#中的泛型与C++中的模板不太相似,在C#泛型中,所有引用类型共享相同的泛型代码,因此它们在编译时都类似地处理泛型类型.这意味着任何编译时使用泛型类型占位符重载您的泛型调用只能通过您在泛型类型本身上提供的任何约束,因为泛型是在实际实现之前编译的.

也就是说,GenericClass<T>在考虑使用它之前编译它(这与C++模板的方式非常不同 - 两种方法各有利弊).所以,如果你有一个不受约束的泛型(比方说,只是T)那么它被认为object是出于重载的目的(粗略地说),但是如果你有一个约束泛型(比如说where T : BaseInterface)那么它被认为BaseInterface是出于重载的目的.

在这种情况下你会看到类似的东西:

public static bool UberEquals<T>(T left, T right) where T : class
{
    return left == right;
}
Run Code Online (Sandbox Code Playgroud)

所以如果你通过以下方式调用它,你会想到:

var s1 = "ello";
var s2 = "Hello";

UberEquals<string>('H' + s1, s2);
Run Code Online (Sandbox Code Playgroud)

因为T是类型string然后它会调用strings ==重载,但它没有,因为你没有约束T,因此在编译时它假定一个最小公分母object并使用objects ==代替.

另一种思考方式:

BaseInterface bi = new ImplementedClass();

var x = TestPolymorphism.CheckInterface(bi);
Run Code Online (Sandbox Code Playgroud)

X将总是BaseInterface在上面说,因为重载在编译时解决,而不是在运行时动态解决.与泛型非常相似,请记住泛型在实现之前已经编译,因此它只能在为了重载解析的目的而将其约束到的任何基类或接口上进行.