简体   繁体   English

C#中通用列表的类型转换

[英]Type conversion for generic lists in C#

I'm trying to figure out why the type conversion is not possible in the first case, but it is possible in the second one. 我试图弄清楚为什么在第一种情况下不能进行类型转换,但在第二种情况下它是可能的。 Please, take a look at the code below: 请看下面的代码:

var strList = new List<string>{"One", "Two", "Three"};
List<object> objList = (List<object>) strList; // <<<< why is not converted? - Case 1

IEnumerable<object> ienumList = strList; // <<<< why is converted?  - Case 2

While the comment referring to covariance and contravariance makes a good point about the underlying principle, I am going to answer in terms of the concrete effects in the presented case: 虽然关于协方差和逆变评论对基本原则提出了一个很好的观点,但我将回答所提出案例中的具体影响:

 List<object> objList = (List<object>) strList; 

objList is writeable. objList是可写的。 It will allow you to do this: 它允许你这样做:

objList.Add(new Object());

However, objList is still the same instance as strList . 然而, objList仍然是相同的实例作为strList You have just added an instance of System.Object to a List<string> ! 您刚刚将一个System.Object实例添加到List<string>

The compiler cannot allow that to happen. 编译器不允许这种情况发生。 Thus, a List<string> cannot be cast to a List<object> . 因此,无法将List<string>强制转换为List<object>

In the second case, on the other hand, you retrieve an enumerable: 另一方面,在第二种情况下,您检索一个可枚举的:

 IEnumerable<object> ienumList = strList; 

There is no way to modify the resulting enumerable, as IEnumerable<T> does not provide any members that mutate the instance. 无法修改生成的可枚举,因为IEnumerable<T>不提供任何改变实例的成员。 Therefore, the type parameter T can be (and is) marked with the out keyword, which allows the presented typecast. 因此,类型参数T可以(并且)用out关键字标记,这允许呈现的类型转换。

Two major concepts play roles here: Type Conversions and Generic Interfaces Variance . 这里有两个主要概念: Type ConversionsGeneric Interfaces Variance Where the variance is the leading one. 方差是最重要的。

Case 1: In List<T> class definition, we do not have variance on generic parameter. 情况1:List<T>类定义中,我们没有泛型参数的差异。 So we do not have any relations defined between List<object> and List<string> . 所以我们没有在List<object>List<string>之间定义任何关系。 They are invariant. 它们是不变的。 Therefore both implicit and explicit type conversion are not possible. 因此,隐式和显式类型转换都是不可能的。

Case 2: List<T> implements IEnumerable<out T> which is covariant generic type, so List<string> can be implicitly cast to IEnumerable<object> 情况2: List<T>实现IEnumerable<out T> ,它是协变泛型类型,因此List<string>可以隐式地转换为IEnumerable<object>

DETAILS: 细节:

Why the variance is not allowed for List<T> , but allowed for IEnumerable<T> ? 为什么List<T>不允许方差,但允许IEnumerable<T>

The point of generics is to provide compile-time type safety. 泛型的关键是提供编译时类型的安全性。 Because List<T> is writable and if there wasn't a compile time check, we could write the following and have a run-time error: 因为List<T>是可写的,如果没有编译时检查,我们可以编写以下内容并产生运行时错误:

List<string> stringList = new List<string>();
stringList.Add("some string"); // we are safe
List<object> objectList = stringList;
objectList.Add((new Object()); // Aargh! 
// we are trying to put an object to a list of strings!

So no unsafe variance for List<T> . 所以List<T>没有不安全的差异。

But IEnumerable<out T> is read-only. IEnumerable<out T>是只读的。 It does not provide a way to modify the referenced instance. 它没有提供修改引用实例的方法。

IEnumerable<object> objectList = new List<string>();
// we can't add a string to the objectList, 
// as `IEnumerable<out T>` is a read-only interface.

So a safe variance is possible. 因此可以实现安全差异。

If you are using framework 3.5 or higher, you can do this: 如果您使用的是框架3.5或更高版本,则可以执行以下操作:

var strList = new List<string>{"One", "Two", "Three"};
List<object> objList = strList.Cast<object>().ToList();

You can take a look at @Hagashen Naidu it has a very good explanation for this case. 你可以看看@Hagashen Naidu它对这个案子有一个非常好的解释。

See the following for an explanation of co and contra-variance. 有关co和contra-variance的说明,请参阅以下内容。 Think it will give clarity on the issue you having: 认为它会清楚你遇到的问题:

http://tomasp.net/blog/variance-explained.aspx/ http://tomasp.net/blog/variance-explained.aspx/

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM