>我创建了一个模板,该模板返回数组中最大值的索引。它有效,但前提是我传入一个奇怪的演员表。
static public int FindMaxIndex<T>( IEnumerable<IComparable<T>> arr )
{
IEnumerator<IComparable<T>> it = arr.GetEnumerator();
if (!it.MoveNext()) return -1;
int index = 1, maxIndex = 0;
IComparable<T> max = it.Current;
while (it.MoveNext())
{
if (max.CompareTo( (T)(it.Current) ) < 0)
{
maxIndex = index;
max = it.Current;
}
++index;
}
return maxIndex;
}
现在使用它:
List<IComparable<Double>> arr = new List<IComparable<Double>>(); // THIS WORKS
List<Double> arr = new List<Double>(); // THIS DOESN'T
后面的列表,也就是我想使用的列表,给出了这个编译器错误:
cannot convert from 'System.Collections.Generic.List<double>' to 'System.Collections.Generic.IEnumerable<System.IComparable<double>>'
这怎么可能?"双"是一个可比的;取自其定义:
public struct Double : IComparable, IFormattable, IConvertible, IComparable<Double>, IEquatable<Double>
我认为其他答案已经解决了为什么您编写的代码没有按照您期望的方式工作,甚至为什么代码在某些情况下会失败。 但是,没有一个答案显示您做您想做的事的方法:
public static int FindMaxIndex<T>( IEnumerable<T> source ) where T : IComparable<T>
{
using( var e = source.GetEnumerator() )
{
if( !e.MoveNext() ) return -1;
T maxValue = e.Current;
int maxIndex = 0;
for( int i = 1; e.MoveNext(); ++i )
{
if( maxValue.CompareTo( e.Current ) < 0 )
{
maxIndex = i;
maxValue = e.Current;
}
}
return maxIndex;
}
}
所以我在这里引入了一个通用约束(where T : IComparable<T>
(。 这告诉编译器,无论T
碰巧是什么,它都会实现IComparable<T>
。
此外,我已将枚举器放在 using
语句中,这将保证调用其 Dispose
方法。
无论如何,现在当你调用这个方法时,它将直接在IEnumerable<double>
上工作,甚至为你推导出类型参数:
var someDoubles = new List<double> { 3, 2, 1 };
Console.WriteLine( FindMaxIndex( someDoubles ) ) // Prints "0";
此外,如果在 static
类中声明了FindMaxIndex
,则可以将 this
关键字放在 source 参数的前面,使其成为扩展方法:
public static int FindMaxIndex<T>( this IEnumerable<T> source ) where T : IComparable<T>
{
// ...
}
现在你可以这样称呼它:
list.FindMaxIndex()
仅当泛型参数是引用类型时,泛型协方差才有效。 由于将值类型作为参数,因此它无法执行任何协变转换。
double
是一个IComparable<double>
,但List<double>
不是一个List<IComparable<double>>
。
也不能允许。考虑:
private class ScrewItUp : IComparable<double>
{
public int CompareTo(double value) => 0;
}
List<IComparable<double>> list = new List<double>(); // you propose that this work.
list.Add(new ScrewItUp()); // What's this supposed to do, then?
on 可以在接口中涉及方差,例如 List<string>
可以传递给IEnumerable<object>
但这只有在方差中涉及的类型都是引用类型时才会发生。
Jon Hanna的答案是正确的。下面的代码有效。
double
可能是一个IComparable<double>
.但是,List<double>
不是List<IComparable<double>>
。需要强制转换列表中的每个元素。不能强制转换整个列表。
List<double> list = new List<double>() { 1,5,3};
Console.WriteLine(FindMaxIndex(list.Cast<IComparable<double>>()));