Foundry

I just don't get something in the generic .NET type. Can someone explain what happens in the following code snippet?

void Main() { IEnumerable<int> ints = new List<int>(); IEnumerable<string> strings = new List<string>(); var rez1=(IEnumerable<object>)ints; //runtime error var rez2=(IEnumerable<object>)strings; //works var rez3=(List<object>)strings; //runtime error } 
+8
generics casting c #
source share
3 answers

Start with the second line, which is easiest.

This works because now the IEnumerable<T> covariant parameter (which makes out in out T ). This means that you are free to use IEnumerable<Derived> for IEnumerable<Base> .

The first line, which seems to be the same, does not work, because int is a value type. Interface variance does not work with value types at all, because value types are not actually inherited from System.Object ; they can be placed in object , but this is not the same. The documentation mentions that

Deviation applies only to reference types; if you specify a value type for a variant type parameter, this type parameter is invariant for the resulting constructed type.

Finally, the third line does not work, because a parameter of type List<T> is invariant. You can see that there is no out in its type parameter; rules forbid because List<T> not an interface:

In the .NET Framework 4, options type options are limited to a common interface and common delegate types.

+11
source share

This is because interface covariance only works with reference types. Int32, of course, is a value type.

This gives additional information: http://blogs.msdn.com/b/ericlippert/archive/2009/11/30/what-s-the-difference-between-covariance-and-assignment-compatibility.aspx

And so: http://ericlippert.com/2011/09/19/inheritance-and-representation/

+2
source share

The definition of each type derived from System.ValueType , with the exception of System.Enum , actually defines two types of things: the type of the heap object and the type of storage location. Instances of the latter can be implicitly converted to the former (creating a copy of the data contained in it), and instances of the former can be explicitly attributed to the latter (similarly); although both types are described by the same System.Type , and although they have the same elements, they behave differently.

A List<AnyClassType> expects to contain a bunch of heap references; whether the list in question is List<String> , List<StringBuilder> , List<Button> or something else, may be of interest to users of the list, but not of interest to the List<T> . If one of the List<Button> sends to IEnumerable<Control> , the one who calls its GetEnumerator() method expects to get an object that will display heap objects that come from Control ; returning from List<Button>.GetEnumerator() will satisfy this expectation. In contrast, if someone were to drop List<Int32> to List<Object> , then who called GetEnumerator() would expect something that displays heap object references, but List<Integer>.GetEnumerator instead it will give something that outputs integers of type values.

You can store Int32 values ​​in a List<Object> or List<ValueType> ; storing an integer in such a list converts it into its heap object form and saves a link to it; calling GetEnumerator() will give something that displays heap links. However, there is no way to indicate that such a list will only contain heap type instances matching Int32 . In C ++ / CLI, it is possible to declare variables of the type "reference to the stored heap evaluation method", but the mechanisms underlying common types in .net cannot work with such types.

0
source share

All Articles