"Double" 没有被转换为 "IComparable<Double>"
"Double" doesn't get cast as "IComparable<Double>"
我创建了一个模板,returns 数组中最大值的索引。它有效,但前提是我传入一个奇怪的列表。
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>>'
怎么会这样? "Double" 是一个 IComparable;取自它的定义:
public struct Double : IComparable, IFormattable, IConvertible, IComparable<Double>, IEquatable<Double>
泛型协变仅在泛型参数是引用类型时有效。因为你有一个值类型作为参数,它不能执行任何协变转换。
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>
但这只有在涉及方差的类型都是引用类型时才会发生。
方向正确。下面的代码有效。
double
可能是 IComparable<double>
。但是 List<double>
不是 List<IComparable<double>>
。需要将每个元素投射到列表中。您不能投射整个列表。
List<double> list = new List<double>() { 1,5,3};
Console.WriteLine(FindMaxIndex(list.Cast<IComparable<double>>()));
我认为其他答案已经解决了您编写代码的原因 and even why the 。但是,none 的答案会告诉您如何做您想做的事情:
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
class中声明了FindMaxIndex
,可以在源参数前加上this
关键字,使其成为扩展方法:
public static int FindMaxIndex<T>( this IEnumerable<T> source ) where T : IComparable<T>
{
// ...
}
现在您可以这样称呼它了:
list.FindMaxIndex()
我创建了一个模板,returns 数组中最大值的索引。它有效,但前提是我传入一个奇怪的列表。
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>>'
怎么会这样? "Double" 是一个 IComparable;取自它的定义:
public struct Double : IComparable, IFormattable, IConvertible, IComparable<Double>, IEquatable<Double>
泛型协变仅在泛型参数是引用类型时有效。因为你有一个值类型作为参数,它不能执行任何协变转换。
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>
但这只有在涉及方差的类型都是引用类型时才会发生。
double
可能是 IComparable<double>
。但是 List<double>
不是 List<IComparable<double>>
。需要将每个元素投射到列表中。您不能投射整个列表。
List<double> list = new List<double>() { 1,5,3};
Console.WriteLine(FindMaxIndex(list.Cast<IComparable<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
class中声明了FindMaxIndex
,可以在源参数前加上this
关键字,使其成为扩展方法:
public static int FindMaxIndex<T>( this IEnumerable<T> source ) where T : IComparable<T>
{
// ...
}
现在您可以这样称呼它了:
list.FindMaxIndex()