13.07.2015 Views

C# in Depth

C# in Depth

C# in Depth

SHOW MORE
SHOW LESS
  • No tags were found...

Create successful ePaper yourself

Turn your PDF publications into a flip-book with our unique Google optimized e-Paper software.

Limitations of generics <strong>in</strong> <strong>C#</strong> and other languages1033.6.1 Lack of covariance and contravarianceIn section 2.3.2, we looked at the covariance of arrays—the fact that an array of a referencetype can be viewed as an array of its base type, or an array of any of the <strong>in</strong>terfacesit implements. Generics don’t support this—they are <strong>in</strong>variant. This is for the sake oftype safety, as we’ll see, but it can be annoy<strong>in</strong>g.WHY DON’T GENERICS SUPPORT COVARIANCE?Let’s suppose we have two classes, Animal and Cat, where Cat derives from Animal. Inthe code that follows, the array code (on the left) is valid <strong>C#</strong> 2; the generic code (onthe right) isn’t:Valid (at compile-time):Animal[] animals = new Cat[5];animals[0] = new Animal();Invalid:List animals=new List();animals.Add(new Animal());The compiler has no problem with the second l<strong>in</strong>e <strong>in</strong> either case, but the first l<strong>in</strong>e onthe right causes the error:error CS0029: Cannot implicitly convert type'System.Collections.Generic.List' to'System.Collections.Generic.List'This was a deliberate choice on the part of the framework and language designers. Theobvious question to ask is why this is prohibited—and the answer lies on the secondl<strong>in</strong>e. There is noth<strong>in</strong>g about the second l<strong>in</strong>e that should raise any suspicion. After all,List effectively has a method with the signature void Add(Animal value)—you should be able to put a Turtle <strong>in</strong>to any list of animals, for <strong>in</strong>stance. However, theactual object referred to by animals is a Cat[] (<strong>in</strong> the code on the left) or a List(on the right), both of which require that only references to <strong>in</strong>stances of Cat are stored<strong>in</strong> them. Although the array version will compile, it will fail at execution time. This wasdeemed by the designers of generics to be worse than fail<strong>in</strong>g at compile time, which isreasonable—the whole po<strong>in</strong>t of static typ<strong>in</strong>g is to f<strong>in</strong>d out about errors before the codeever gets run.NOTE So why are arrays covariant? Hav<strong>in</strong>g answered the question about whygenerics are <strong>in</strong>variant, the next obvious step is to question why arrays arecovariant. Accord<strong>in</strong>g to the Common Language Infrastructure AnnotatedStandard (Addison-Wesley Professional, 2003), for the first edition thedesigners wished to reach as broad an audience as possible, which <strong>in</strong>cludedbe<strong>in</strong>g able to run code compiled from Java source. In other words, .NET hascovariant arrays because Java has covariant arrays—despite this be<strong>in</strong>g aknown “wart” <strong>in</strong> Java.So, that’s why th<strong>in</strong>gs are the way they are—but why should you care, and how can youget around the restriction?Licensed to Rhona Hadida

Hooray! Your file is uploaded and ready to be published.

Saved successfully!

Ooh no, something went wrong!