[英]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 Conversions和Generic 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.