我有以下界面和类:
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
答案 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
只是因为你没有改变泛型类型,因此编译器不必在这一行推断出方差信息(它没有)。