将List<int>转换为IEnumerable<IComparable>

9
我可以将int隐式转换为IComparable。我还可以将List或数组转换为IEnumerable。但是为什么不能将List隐式转换为IEnumerable呢?我在.net framework 4.5和Visual Studio 2012 Ultimate中进行了测试。用于测试的代码:
IComparable test1;
int t1 = 5;
test1 = t1; //OK

IEnumerable<int> test2;
List<int> t2 = new List<int>();
int[] t3 = new int[] { 5, 6 };
test2 = t2; //OK
test2 = t3; //OK

TabAlignment[] test;

IEnumerable<IComparable> test3;
test3 = t2; //error Cannot implicitly convert type 'System.Collections.Generic.List<int>' to 'System.Collections.Generic.IEnumerable<System.IComparable>'. An explicit conversion exists (are you missing a cast?)
2个回答

13
通用的协变性不适用于值类型。因此,虽然您可以这样做,但需要对每个值进行装箱:
IEnumerable<IComparable> test3 = t2.Cast<IComparable>();

因此,虽然这是有效的,因为string是引用类型:

List<string> strings = new List<string>();
IEnumerable<IComparable> comparables = strings;

...相应的方法对于List<int>无效,你需要在进行操作时将其装箱。


阅读了您的答案并与我的进行了比较(然后在代码中进行了测试),我意识到在这种情况下我的答案是错误的,因为它处理的是从List -> List而不是List -> IEnumerable的转换,但我困惑的是为什么会有差别。您能解释一下吗? - Jon Egerton
@JonEgerton:我猜你在那个评论中放了泛型类型参数,但我看不到它们。再试一次,在代码相关的部分周围加上反引号。 - Jon Skeet
1
@JonEgerton:好的,仔细阅读了你的回答,然后再次读了一遍你的评论……问题出在List<T>不支持类型协变,但是IEnumerable<T>是支持的(从.NET 4开始)。类永远不能是协变的。在MSDN上搜索“泛型协变”以了解更多细节 :) - Jon Skeet
我想我明白了,但我会跟进一下 - 感谢您的反馈。 - Jon Egerton

2

泛型列表经常会让人感到困惑,但基本上如果您将其泛化,它会更有意义:

考虑下面的设置:

public interface IA{
}

public class A : IA{
}

var listA = new List<A>();

以下代码行将无法正常工作:
List<IA> listI = ListA;

本质上这是因为,尽管 A:IAList<I>不等于List<A> - 它们是完全独立的类型。

但您可以使用Cast方法轻松执行转换:

listI = ListA.Cast<IA>();

所以在你的情况下,你可以这样做

test3 = t2.Cast<IComparable>();

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接