我在问题C#'s equivalent of Java's <? extends Base> in generics中读过关于协方差和反演的问题,但是将我的项目切换到.net 4.0似乎没有用。
考虑以下类构造函数:
public Matrix(IList<RowVector> rows) {
if (!Vector.AreDimensionsEqual(rows)) {
throw new ArgumentException("foo");
}
for (int i = 0; i < rows.Length; ++i) {
for (int j = 0; j < rows[0].Length; ++j) {
Components[i][j] = rows[i].Components[j];
}
}
}
和方法AreDimensionsEqual(IList<Vector> vectors)
:
public static bool AreDimensionsEqual(IList<Vector> vectors) {
int dimensions = vectors[0].Dimension;
for (int i = 1; i < vectors.Count; ++i) {
if (vectors[i].Dimension != dimensions) {
return false;
}
}
return true;
}
此处rows
构造函数中的Matrix
是RowVector
个对象的列表,我正在尝试将其用作需要列表{的方法调用的参数{1}}个对象。 Vector
是RowVector
的子类型。
我最熟悉Java,所以如果我在那里编程,我会将Vector
的方法签名定义为AreDimensionsEqual
,但这种语法在C#中不可用。
还有什么我想念的吗?
答案 0 :(得分:4)
IList&lt; T&gt; 中的泛型类型参数T
不是协变的。
但IEnumerable<out T>中的泛型类型参数T
是协变的(请注意out keyword)。
因此,您可以更改 AreDimensionsEqual 方法以使用 IEnumerable&lt; Vector&gt; 参数:
public static bool AreDimensionsEqual(IEnumerable<Vector> vectors)
{
int dimensions = vectors.First().Dimension;
return vectors.All(v => v.Dimension == dimensions);
}
给出的代码在功能上等同于 AreDimensionsEqual 方法,如问题所示。
答案 1 :(得分:3)
您无法执行此操作,因为IList
在其通用参数中不变。作为无法执行此操作的示例,请考虑以下类层次结构:
class A
{
}
class B : A
{
}
class C : A
{
}
现在想象以下工作:
IList<A> listOfA = new List<B>();
listOfA.Add( new C() );
我们刚刚将一个C
类型的项目添加到类型为List<B>
的 的集合中。我们无法做到这一点。但就listOfA.Add
所知,它只是A
和C
的列表,添加到A
列表是完全合理的。