如何将IList <t1>分配给IList <t2>,其中T1是T2的子类型?</t2> </t1>

时间:2014-08-03 00:30:36

标签: c# generics inheritance interface

序:

我在问题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构造函数中的MatrixRowVector个对象的列表,我正在尝试将其用作需要列表{的方法调用的参数{1}}个对象。 VectorRowVector的子类型。

我最熟悉Java,所以如果我在那里编程,我会将Vector的方法签名定义为AreDimensionsEqual,但这种语法在C#中不可用。

还有什么我想念的吗?

2 个答案:

答案 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所知,它只是AC的列表,添加到A列表是完全合理的。