I just learned that having a generic argument as the type of an out
parameter forces that generic type to be invariant. This is surprising to me. I thought out
parameters are treated the same as return types (i.e. if the generic parameter is covariant, then it can be used in as an out
out parameter), since they are both "outputs" of a method.
After a bit of investigation, I realised that you can't do this:
public class Program {
public static void Main() {
// cannot convert from 'out object' to 'out string'
F(out object s); // passing an out object
}
public static void F(out string o) {
o = null;
}
}
This explains why out
parameters must be invariant. However, I still don't understand why you can't do this. As is commonly known, out
parameters are just another way of returning a value. F
could be rewritten with a return value, and it will work:
// This is the semantically equivalent version of the above, just without "out"
public class Program {
public static void Main() {
object s = F();
}
public static string F() {
return null;
}
}
So why doesn't the first code snippet compile? Does using out
allow F
to do something that can't be done with return values, that will break type-safety if an out object s
were passed to it?
I found this question, which is about converting the other way - from a derived class to a base class, which clearly isn't possible. You can't assign the return value of a method that returns a object
to a variable of type string
, can you?
What I'm asking is, since you can assign the return value of a method that returns string
to a variable of type object
, why can't you do the same with out
parameters? That is, why can't you pass an out object
to a out string
parameter?
I also read the docs and the spec, but they never mentioned anything about the fact that you have to pass the exact same type into a out
parameter, let alone explain why you have to do it.
out
is still in c# mainly for compatibility reasons, and that calls to external/unmanaged libraries tend to rely onout
, and while what you describe is valid in c#, it isn't necessarily valid in other languages (AFAIK) – Hazembool TryGetValue(TKey key, out TValue value)
inDictionary
– Narbada