为什么我不能将基础引用转换为派生类实现的变体接口?

时间:2016-12-09 11:59:03

标签: c# generics casting

我有以下界面和类:

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

1 个答案:

答案 0 :(得分:0)

问题是TestClass确实不是ITest<T1, T2>。它与界面无关,因此您不能只写:

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

另一方面,非通用TestClass与通用的(TestClass<T1, T2>)new TestClass(); // will fail at run time... 相关。因此,以下说明实际上是一个向下的指示:

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

Downcast可能在运行时成功或失败,具体取决于实际对象是否为派生类型。编译将始终成功。

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

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

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

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

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

您的最后一行有效,即:

ansible --version
ansible 2.2.0.0

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