C# 如何分配IList<;T1>;对IList<;T2>;其中T1是T2的一个亚型? 前言:

C# 如何分配IList<;T1>;对IList<;T2>;其中T1是T2的一个亚型? 前言:,c#,generics,inheritance,interface,C#,Generics,Inheritance,Interface,我在问题中读到了协方差和逆变,但将我的项目切换到.NET4.0似乎不起作用 考虑以下类构造函数: public Matrix(IList<RowVector> rows) { if (!Vector.AreDimensionsEqual(rows)) { throw new ArgumentException("foo"); } for (int i = 0; i < rows.Length; ++i) { for (

我在问题中读到了协方差和逆变,但将我的项目切换到.NET4.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];
        }
    }
}
公共矩阵(IList行){
如果(!Vector.AreDimensionsEqual(行)){
抛出新的ArgumentException(“foo”);
}
对于(int i=0;i
而方法
是dimensionsequal(IList向量)

public static bool aresdimensionsequal(IList向量){
整数维=向量[0]。维;
对于(int i=1;i
这里,
矩阵
构造函数中的
行向量
对象的列表,我试图将其用作需要
向量
对象列表的方法调用的参数<代码>行向量
向量
的子类型


我对java很熟悉,所以如果我在那里编程,我会把代码签名定义为<代码> AcsixSimulase<代码> >代码> AsixEngaseLILL(ILIST

),因为代码< ILIST>代码>在其通用参数中是不变的,所以不能这么做。作为一个为什么不能这么做的例子,考虑下面的类层次:

class A
{
}

class B : A
{
}

class C : A
{
}
现在想象一下,下面的方法是有效的:

IList<A> listOfA = new List<B>();
listOfA.Add( new C() );
IList listOfA=新列表();
添加(新的C());

我们只是在一个真正属于
List
类型的集合中添加了一个
C
类型的项。我们不能这样做。但就
listOfA.Add
所知,它只是
a
的列表,而
C
a
列表中添加ILS中的泛型参数
t
是完全合理的t不是协变的

但是中的泛型类型参数
T
是协变的(请注意)

因此,您可以更改AreDimensionsEqual方法,以使用IEnumerable参数:

    public static bool AreDimensionsEqual(IEnumerable<Vector> vectors)
    {
        int dimensions = vectors.First().Dimension;
        return vectors.All(v => v.Dimension == dimensions);
    }
public static bool aresdimensionsequal(IEnumerable vectors)
{
int dimensions=vectors.First().Dimension;
返回向量.All(v=>v.Dimension==dimensions);
}

给定的代码在功能上等同于问题中所示的AreDimensionsEqual方法。

您不能。您必须将其转换为其他类型的列表。使用
IEnumerable
作为AreDimensionsEqual方法的参数(然后在其主体中使用foreach循环或Linq表达式…)如何?我已经编辑了你的标题。请参见“”,其中的共识是“不,他们不应该”.Variance在Java和C#中的实现方式不同。Java使用了站点差异,而C#使用了声明站点差异。这两者是不等价的。因此,Java中可以使用的模式在C#中没有等价的形式。这是一个非常有趣的解决方案。我知道LINQ,但从未花时间尝试解决但我注意到的一件事(我以前在另一个案例中使用IEnumerable时遇到过)是,我收到了关于“可能多次枚举IEnumerable”的警告,可能来自Resharper。@agent154,我答案代码中的LINQ表达式在功能上与您问题中的代码相同。但我认为您的目的是检查任何两个向量是否具有相同的维数(或者您确实只想检查任何向量是否具有与第一个向量相同的维数?)如果您不正确地使用Linq会导致应用程序运行缓慢,Resharper会发出警告。有时,由于Resharper无法真正理解程序上下文,因此会发出错误的警告-但在任何情况下,都应该仔细检查此警告是否成立或只是错误警报…:)您的假设是正确的。我想确保所有的向量都是相同的维数。如果一个不是,那么它就会失败。@agent154r#警告您这一点,因为
IEnumerable
可以是任何东西。例如,枚举它可以执行SQL查询以生成结果。ReSharper不知道可枚举的后面是什么,只是假设默认情况下不应该多次枚举它。调用myEnumerable=myEnumerable.ToList()以枚举一次,然后重新使用。请注意,
ICollection
/
IReadOnlyCollection
可以安全地多次枚举。我不明白为什么不能合理地做到这一点。。。如果C扩展了B,B扩展了A,那么人们会认为,如果你创建了一个A对象的列表,那么无论你调用A的什么方法都应该存在于B和C中。@agent154在他的示例中,
listOfA
的类型实际上是
list
    public static bool AreDimensionsEqual(IEnumerable<Vector> vectors)
    {
        int dimensions = vectors.First().Dimension;
        return vectors.All(v => v.Dimension == dimensions);
    }