C# &引用;“双”字;不';t被选为“演员”;i可比较<;双倍>&引用;

C# &引用;“双”字;不';t被选为“演员”;i可比较<;双倍>&引用;,c#,generics,covariance,C#,Generics,Covariance,我创建了一个模板,它返回数组中最大值的索引。这是可行的,但前提是我通过了一个奇怪的演员名单 static public int FindMaxIndex<T>( IEnumerable<IComparable<T>> arr ) { IEnumerator<IComparable<T>> it = arr.GetEnumerator(); if (!it.MoveNext()) retur

我创建了一个模板,它返回数组中最大值的索引。这是可行的,但前提是我通过了一个奇怪的演员名单

    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;
    }
静态公共int FindMaxIndex(IEnumerable arr)
{
IEnumerator it=arr.GetEnumerator();
如果(!it.MoveNext())返回-1;
int-index=1,maxIndex=0;
i可比较最大值=it.电流;
while(it.MoveNext())
{
如果(最大比较值((T)(it.Current))<0)
{
maxIndex=索引;
最大值=it.电流;
}
++指数;
}
返回最大索引;
}
现在使用它:

    List<IComparable<Double>> arr = new List<IComparable<Double>>(); // THIS WORKS
    List<Double> arr = new List<Double>(); // THIS DOESN'T
List arr=new List();//这很有效
List arr=新列表();//这并不重要
后面的列表是我要使用的,它给出了以下编译器错误:

cannot convert from 'System.Collections.Generic.List<double>' to 'System.Collections.Generic.IEnumerable<System.IComparable<double>>'
无法从“System.Collections.Generic.List”转换为“System.Collections.Generic.IEnumerable”
这怎么可能?“Double”是一个不可比较的词;根据其定义:


public struct Double:IComparable、ifformattable、IConvertible、IComparable、IEquatable
泛型协方差仅在泛型参数为引用类型时有效。因为您有一个值类型作为参数,所以它不能执行任何协变转换。

double
是一个
i可比较的
,但
List
不是一个
列表

也不能允许这样做。考虑:

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?
private-class-ScrewItUp:i可比较
{
公共整数比较(双值)=>0;
}
列表=新列表();//你建议这项工作。
list.Add(新的ScrewItUp());//那这是怎么回事?
On可以在接口中包含差异,例如,
List
可以传递给
IEnumerable
,但只有当差异中包含的类型都是引用类型时,才会发生这种情况。

方向正确。下面的代码起作用

double
可能是一个
i可比较的
。但是
列表
不是
列表
。需要强制转换列表中的每个元素。您不能强制转换整个列表

List<double> list = new List<double>() { 1,5,3};
Console.WriteLine(FindMaxIndex(list.Cast<IComparable<double>>()));
List List=newlist(){1,5,3};
Console.WriteLine(FindMaxIndex(list.Cast());

我认为其他的答案已经说明了为什么你的代码是这样写的,甚至为什么会这样。但是,没有一个答案能告诉你如何做你想做的事情:

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;
    }
}
此外,如果在
静态
类中声明了
FindMaxIndex
,则可以将
this
关键字放在源参数前面,使其成为扩展方法:

public static int FindMaxIndex<T>( this IEnumerable<T> source ) where T : IComparable<T>
{
    // ...
}

如果您使用引用类型而不是double,问题代码将失败,同样的方法。@Evk当double是一个类时,它在我的机器上编译得很好。我的坏,是我方面的一个问题。不相关但。。。这就是为什么我更喜欢C++:- OP正在执行转换为 IcDeaby,这是不同的,可以是协变的。@ Servy是的,我打算在结尾提到这个,但后来我想我在开始时提到过,所以在你评论时已经添加了。@ NuriasDimiar,我看到了。这就是为什么我最后把它作为可选的。OP的帖子中并没有任何东西表明它是必须的。因为他们似乎不知道泛型约束,所以我假设他们也不知道扩展方法。很好。为什么会有反对票,你能至少留下一些评论吗?
public static int FindMaxIndex<T>( this IEnumerable<T> source ) where T : IComparable<T>
{
    // ...
}
list.FindMaxIndex()