协方差在C#数组中被打破了吗?

JE4*_*E42 18 c# mono covariance type-mismatch

考虑ITest使用covariant类型参数T的通用Test接口,实现接口的泛型类,以及类A和子类B:

interface ITest<out T> 
{    
  T prop{ get;}
}
class Test<T> : ITest<T>
{    
    public T prop{ get {
       return default(T);    
    }}
}
class A {    
}
class B: A {    
}
Run Code Online (Sandbox Code Playgroud)

以下代码编译时没有错误但会抛出运行时异常System.ArrayTypeMismatchException:

ITest<A>[] a = new ITest<A>[1];
a[0] = new Test<B>(); //<-- throws runtime exception
Run Code Online (Sandbox Code Playgroud)

但是这段代码运行得很好:

ITest<A> r = new Test<B>();
Run Code Online (Sandbox Code Playgroud)

这已经在Mono 2.10.2(Unity3d 4.1)上进行了测试.我认为这与数组中破坏的协方差有关(参见http://blogs.msdn.com/b/ericlippert/archive/2007/10/17/covariance-and-contravariance-in-c-part-two- array-covariance.aspx).

我不清楚为什么在分配数组插槽时发生的类型检查不考虑协方差.

Pha*_*rap 2

我已经在 Windows 7 上使用 .Net 4 在 VS2010 中编译并测试了给定的代码,它工作正常,它没有给出运行时异常,因此看来您的问题与 Mono 或 Unity 相关。

对于给定的代码,很难对问题是什么做出假设。异常的确切类型和其他一些测试用例(即不使用接口的变体)将有助于缩小确切的问题范围,但这是 Mono|Unity 社区需要解决的问题。

至于它与那篇文章的链接,是无关的。

文章描述的是以下情况:

class A { }
class B: A { }
class C: A { }

A[] a = new B[1];
a[0] = new C(); //<-- throws ArrayTypeMismatchException
Run Code Online (Sandbox Code Playgroud)

为了简化埃里克在他的文章中所说的内容:

a 是一个变量,可以保存从 A 继承的任何类型的数组。

a 被分配了 B 的数组,因此 a 是 B 的数组。

当用户尝试将新的 C 分配给 a 的元素时,会出现类型不匹配,因为 a 实际上是 B 的数组,因此将 C 分配给 a 的元素相当于尝试将新的 C 分配给变量使得 B 像这样:

B b = new C();
Run Code Online (Sandbox Code Playgroud)

将 a 指定为 C 数组也会出现类似的问题。

然而,由于 a 被定义为能够保存 A 的数组,因此用户可以分配 A 的数组,这将允许它接受 B 和 C 的值。

正是因为如此,您问题中的代码似乎与此问题相关,但实际上并不是因为 a 被分配为 ITest 数组,这意味着它应该能够存储 ITest 类型并且运行时错误被抛出的原因是 Mono 或 Unity 运行时的错误。