10

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

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";
    }
}

然后当我打电话时:

NewClass nc = new NewClass();
ImplementedClass impClass = new ImplementedClass();
Console.WriteLine("The result is " + impClass.WhoIAm(nc));

我有“结果是 BaseInterface”

我期待“结果是 NewInterface”作为 nc 实现 BaseClass 和NewClass
什么是获得“NewClass”结果的最佳方法?

谢谢

4

1 回答 1

17

请记住,对于泛型方法,非虚拟方法调用仍然在泛型本身的编译时解决,而不是在泛型实现的编译时解决。

因此:

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

将解决需要 a 的重载,BaseInterface因为无论T实际类型如何,这都是您将其限制为的重载。

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

也就是说,GenericClass<T>在考虑使用它之前先编译你的(这与 C++ 处理模板的方式非常不同——这两种方法都有其优点和缺点)。所以,如果你有一个不受约束的泛型(比如 just T),那么它被认为object是为了重载(粗略地说),但是如果你有一个受约束的泛型(比如where T : BaseInterface),那么它被认为BaseInterface是为了重载的目的。

在这种情况下,您会看到类似的内容:

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

所以你会想,如果你这样称呼它:

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

UberEquals<string>('H' + s1, s2);

因为Tis typestring那么它会调用strings==重载,但它不会,因为你没有 constrained T,因此在编译时它假定一个最小公分母object并使用objects==代替。

另一种思考方式:

BaseInterface bi = new ImplementedClass();

var x = TestPolymorphism.CheckInterface(bi);

X 总是BaseInterface在上面说,因为重载是在编译时解决的,而不是在运行时动态解决的。与泛型非常相似,请记住泛型是在实现之前编译的,因此它只能在任何基类或接口上进行,以实现重载决议。

于 2012-05-30T19:51:30.920 回答