In C#, the out
keyword can be used in two different ways.
-
As a parameter modifier in which an argument is passed by reference
class OutExample { static void Method(out int i) { i = 44; } static void Main() { int value; Method(out value); // value is now 44 } }
-
As a type parameter modifier to specify covariance.
// Covariant interface. interface ICovariant<out R> { } // Extending covariant interface. interface IExtCovariant<out R> : ICovariant<R> { } // Implementing covariant interface. class Sample<R> : ICovariant<R> { } class Program { static void Test() { ICovariant<Object> iobj = new Sample<Object>(); ICovariant<String> istr = new Sample<String>(); // You can assign istr to iobj because // the ICovariant interface is covariant. iobj = istr; } }
My question is: why?
To a beginner, the connection between the two doesn't seem intuitive. The use with generics doesn't seem to have anything to do with passing by reference.
I first learned what out
was in relation to passing arguments by reference, and this hindered my understanding of the use of defining covariance with generics.
Is there a connection between these uses that I'm missing?
Best Answer
There is a connection, however it is a little loose. In C# the keywords ´in´ and ´out´ as their name suggest stand for input and output. This is very clear in the case of output parameters, but less clean what it have to do with template parameters.
Lets take a look at the Liskov substitution principle:
See how contravariance is associated with input and covariance is associated with output? In C# if you flag a template variable with
out
to make it covariant, but please note you can only do this if the mentioned type parameter only appears as output (function return type). So the following is invalid:Similary if you flag a type parameter with
in
, that means you can only use it as input (function parameter). So the following is invalid:So to summarize, the connection with the
out
keyword is that with function parameters it means that it is an output parameter, and for type parameters it means that the type is only used in output context.System.Func
is also a good example what rwong mentioned in his comment. InSystem.Func
all input parameters ar flaged within
, and the output parameter is flaged without
. The reason is exactly what I described.