Take the following:
class A {}
class B : A {}
class C
{
C()
{
var b = new B();
Foo(b);
Foo2(ref b); // <= compile-time error:
// "The 'ref' argument doesn't match the parameter type"
}
void Foo(A a) {}
void Foo2(ref A a) {}
}
Why does the above compile-time error occur? This happens with both ref and out arguments.
=============
UPDATE: I used this answer as the basis for this blog entry:
Why do ref and out parameters not allow type variation?
See the blog page for more commentary on this issue. Thanks for the great question.
=============
Let's suppose you have classes
Animal,Mammal,Reptile,Giraffe,TurtleandTiger, with the obvious subclassing relationships.Now suppose you have a method
void M(ref Mammal m).Mcan both read and writem.No. That variable could contain a
Turtle, butMwill assume that it contains only Mammals. ATurtleis not aMammal.Conclusion 1:
refparameters cannot be made "bigger". (There are more animals than mammals, so the variable is getting "bigger" because it can contain more things.)No.
Mcan write tom, andMmight want to write aTigerintom. Now you've put aTigerinto a variable which is actually of typeGiraffe.Conclusion 2:
refparameters cannot be made "smaller".Now consider
N(out Mammal n).No.
Ncan write ton, andNmight want to write aTiger.Conclusion 3:
outparameters cannot be made "smaller".Hmm.
Well, why not?
Ncannot read fromn, it can only write to it, right? You write aTigerto a variable of typeAnimaland you're all set, right?Wrong. The rule is not "
Ncan only write ton".The rules are, briefly:
1)
Nhas to write tonbeforeNreturns normally. (IfNthrows, all bets are off.)2)
Nhas to write something tonbefore it reads something fromn.That permits this sequence of events:
xof typeAnimal.xas anoutparameter toN.Nwrites aTigerinton, which is an alias forx.Turtleintox.Nattempts to read the contents ofn, and discovers aTurtlein what it thinks is a variable of typeMammal.Clearly we want to make that illegal.
Conclusion 4:
outparameters cannot be made "larger".Final conclusion: Neither
refnoroutparameters may vary their types. To do otherwise is to break verifiable type safety.If these issues in basic type theory interest you, consider reading my series on how covariance and contravariance work in C# 4.0.