【问题标题】:Why can't I cast base reference to a variant interface implemented by derived class?为什么我不能将基引用转换为派生类实现的变体接口?
【发布时间】:2016-12-09 11:59:03
【问题描述】:

我有以下接口和类:

private interface ITest<in T1, out T2>
{
}

private class TestClass
{
}

private class TestClass<T1, T2> : TestClass, ITest<T1, T2>
{
}

有了这些,我可以做到:

    TestClass testBase = new TestClass<Parent, Child> ();

    TestClass<Parent, Child> testGeneric = (TestClass<Parent, Child>)testBase; // Works fine
    ITest<Parent, Parent> testInterface = (ITest<Parent, Parent>)testGeneric; // Works fine

但如果我尝试将两者结合起来,我就做不到:

    ITest<Parent, Parent> testInterface = (ITest<Parent, Parent>)testBase; // Fail!

为什么我不能直接在这里投射?这只是 C# 转换或变体接口的限制吗?

如果接口的类型参数与泛型类的类型完全匹配,它实际上是有效的:

    ITest<Parent, Child> testInterfaceExact = (ITest<Parent, Child>)testBase; // Works

【问题讨论】:

标签: c# generics casting


【解决方案1】:

问题是TestClass 真的不是ITest&lt;T1, T2&gt;。它与接口无关,因此您不能只写:

(ITest<T1, T2>)new TestClass();

另一方面,非泛型TestClass 与作为其基础的泛型相关。所以,下面的指令其实是一个downcast:

(TestClass<T1, T2>)new TestClass();  // will fail at run time...

Downcast 在运行时可能会成功或失败,这取决于实际对象是否属于派生类型。编译总会成功的。

现在,如果您想要对派生对象进行基本引用,那很好。但是,如果您希望将其转换为仅派生类已知的任何内容,例如您的接口,则必须先执行向下转换:

TestClass derived = new TestClass<T1, T2>();
ITest<T1, T2> interf = (TestClass<T1, T2>)derived;

您甚至不必强制转换为接口,因为泛型类已经实现了该接口。

变体类型参数的问题变得更糟。如果编译器无法访问泛型参数的方差信息,则无法检查是否可以进行强制转换。转换为泛型类后,编译器将能够正确推断方差并分配引用:

TestClass derived = new TestClass<Parent, Child>();
ITest<Parent, Parent> interf = (TestClass<Parent, Child>)derived;

你的最后一行有效,那就是:

ITest<Parent, Child> testInterfaceExact = (ITest<Parent, Child>)testBase;

只是因为您没有更改泛型类型,因此编译器不必在这一行推断方差信息(它没有)。

【讨论】:

    猜你喜欢
    • 2013-09-30
    • 1970-01-01
    • 2016-06-14
    • 2011-05-07
    • 2012-05-14
    • 1970-01-01
    • 2023-03-12
    • 2012-10-17
    相关资源
    最近更新 更多