我创建了一个模板,它返回数组中最大值的索引。它有效,但只有当我传入一个奇怪的演员列表时。
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>
答案 0 :(得分:4)
我认为其他答案已经解决了为什么您的代码编写为isn't working the way you'd expect,甚至为什么code will fail in some cases。但是,没有一个答案显示你想要的方式:
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";
此外,如果在FindMaxIndex
类中声明static
,您可以将this
关键字放在source参数前面,使其成为扩展方法:
public static int FindMaxIndex<T>( this IEnumerable<T> source ) where T : IComparable<T>
{
// ...
}
现在你可以这样打电话了:
list.FindMaxIndex()
答案 1 :(得分:3)
通用协方差仅在泛型参数是引用类型时有效。因为您有一个值类型作为参数,所以它不能执行任何协变转换。
答案 2 :(得分:3)
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>
,但这只有在方差中涉及的类型都是引用类型时才会发生。
答案 3 :(得分:-2)
Jon Hanna's answer是正确的方向。下面的代码工作。
double
可能是IComparable<double>
。但是List<double>
不是List<IComparable<double>>
。需要在列表中转换每个元素。你不能施放整个清单。
List<double> list = new List<double>() { 1,5,3};
Console.WriteLine(FindMaxIndex(list.Cast<IComparable<double>>()));