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

本文关键字:泛型类 调用 不适用 适用于 多态性 | 更新日期: 2023-09-27 18:35:43

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

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));

我有"结果是基本接口"

我期待有"结果是新接口"作为nc实现BaseClass和NewClass
获得"NewClass"作为结果的最佳方法是什么?

谢谢

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

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

因此:

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

将解析为需要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;
}

所以你会想,如果你用以下方式调用这个:

var s1 = "ello";
var s2 = "Hello";
UberEquals<string>('H' + s1, s2);

由于Tstring类型,因此它会调用string ==重载,但它没有,因为你没有约束T,因此在编译时它假设object的最小公分母并改用object ==

另一种思考方式:

BaseInterface bi = new ImplementedClass();
var x = TestPolymorphism.CheckInterface(bi);

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