Why Animals[] animals = new Cat[5] compiles, but List animals = new List() does not?

Arrays have a weird history with variance in .NET. Proper support for variance was added in the 2.0 version of the CLR - and the language in C# 4.0. Arrays however, have always had a covariant behavior.

Arrays have a weird history with variance in .NET. Proper support for variance was added in the 2.0 version of the CLR - and the language in C# 4.0. Arrays however, have always had a covariant behavior.

Eric Lippert goes into great detail on that in a blog post. The interesting bit: Ever since C# 1.0, arrays where the element type is a reference type are covariant. This is perfectly legal: Animal animals = new Giraffe10; Since Giraffe is smaller than Animal, and “make an array of�

Is a covariant operation on types, Giraffe is smaller than Animal, so an instance fits into that variable. Unfortunately, this particular kind of covariance is broken. It was added to the CLR because Java requires it and the CLR designers wanted to be able to support Java-like languages.

We then up and added it to C# because it was in the CLR. This decision was quite controversial at the time and I am not very happy about it, but there’s nothing we can do about it now. Emphasis added by myself.

That's precisely why array covariance is broken. The fact that we allow it means that we allow what should be an error that gets caught at compilation time to be ignored, and instead get caught at runtime. I'm not completely statisfied with this short-answer.

I want to know it in a more detail, with some insight into how compiler handles the difference ... The compiler handles the difference easily enough. The compiler has a whole bunch of code that determines when one type is compatible with another. Part of that code deals with array-to-array conversions.

Part of that code deals with generic-to-generic conversions. The code is a straightforward translation of the relevant lines of the specification.... and how it generates IL and all. There is no need to generate any IL whatsoever for a covariant array conversion.

Why would we need to generate IL for a conversion between two reference-compatible types? It's like asking what IL we generate for converting a string to an object. A string already is an object, so there's no code generated.

Ok I'm confused about that last bit and maybe this should be another question, but I thought the output of the compiler was IL. Unless you're saying that the compiler simply doesn't do anything special when the setting a variable that is assignment compatible with the value. – Conrad Frix Sep 28 at 20:05 1 Out of interest Eric, do you happen to know if the JIT compiler is smart enough to avoid the execution-time type check on storing an element in a reference type array when the "known" type of the array is sealed?

For example, writing "foo" via a object reference needs checking because it could be a Button, but writing "foo" via a string reference must be valid (in terms of the type), because it couldn't refer to a value of any type other than an actual string array. – Jon Skeet Sep 28 at 20:05 1 @ConradFrix: Right, we just generate IL that assigns the variable, assuming that you are in fact assigning a variable. If the value is of a type that is assignment compatible with the type of the variable then by definition, you don't need to generate any conversion code.

That's what "assignment compatible" means. The question was not "what code is generated on an assignment" but rather "what code is generated on a conversion". No code is generated on a conversion from string to object, just as no code is generated on a conversion from string to object.

– Eric Lippert Sep 28 at 21:18 @JonSkeet: I do not know for sure but I would definitely be very surprised if the jitter generated a type check when the type was statically known to be sealed. – Eric Lippert Sep 28 at 21:18 @EricLippert: Me too. One day I'll venture into cordbg to check... – Jon Skeet Sep 28 at 21:27.

I think Jon Skeet explained it rather well, however if you need that "Ahah" moment consider how generics work. A generic class like List is, for most purposes, treated externally as a normal class. E.g.

When you say List() the compiler says ListString() (which contains strings) and the compiler can't be smart enough to convert a ListString to a ListObject by casting the items of its internal collection. From reading MSDN blog post, it appears that covariance and contravariance is supported in . NET 4.0 when when working with delegates and interfaces.It mentions Eric's articles also in the second sentence.

I cant really gove you an answer,but what I can give you is a way to a solution, that is you have to find the anglde that you relate to or peaks your interest. A good paper is one that people get drawn into because it reaches them ln some way.As for me WW11 to me, I think of the holocaust and the effect it had on the survivors, their families and those who stood by and did nothing until it was too late.

Related Questions