Type conversion for shared lists in C #

I am trying to understand why type conversion is not possible in the first case, but it is possible in the second. Please check out 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 
+5
source share
4 answers

While the commentary on covariance and contravariance gives a good idea of ​​the underlying principle, I am going to answer in terms of specific effects in the case presented:

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

objList can be written. This will allow you to do this:

 objList.Add(new Object()); 

However, objList remains the same instance as strList . You just added an instance of System.Object to the List<string> !

The compiler cannot allow this. Thus, a List<string> cannot be assigned to a List<object> .

In the second case, on the other hand, you get an enumerable:

 IEnumerable<object> ienumList = strList; 

It is not possible to modify the resulting enumeration number because IEnumerable<T> does not expose any members that mutate the instance. Therefore, a parameter of type T can be (and is) labeled with the keyword out , which allows the presented type.

+9
source

Two basic concepts are presented here: Type Conversions and General Interface Deviations . Where variance is leading.

Case 1: In the definition of List<T> , we do not have variance for a common parameter. So we have no relationship between List<object> and List<string> . They are invariant. Therefore, implicit and explicit type conversion is not possible.

Case 2: List<T> implements IEnumerable<out T> , which is a covariant generic type, so List<string> can be implicitly cast to IEnumerable<object>

DETAILS:

Why is variance not allowed for List<T> but allowed for IEnumerable<T> ?

The point of generics is to provide compilation type security. Since List<T> is writable and if there was no compile time check, we could write the following and have a run-time error:

 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, unsafe variance for List<T> .

But IEnumerable<out T> is read-only. It does not provide a way to modify the reference 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. 

Thus, there is a safe dispersion.

+2
source

If you are using a framework of 3.5 or higher, you can do this:

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

You can take a look at @Hagashen Naidu, he has a very good explanation for this case.

0
source

For an explanation of co and contra dispersion, see the following. Think this will give clarity to the question that you have:

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

-1
source

Source: https://habr.com/ru/post/1263203/


All Articles