C# 如何分配IList<;T1>;对IList<;T2>;其中T1是T2的一个亚型? 前言:
我在问题中读到了协方差和逆变,但将我的项目切换到.NET4.0似乎不起作用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 (
考虑以下类构造函数:
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);
}