How is method group overload resolution different to method call overload resolution?
The following code doesn't compile (error CS0123: No overload for 'System.Convert.ToString(object)' matches delegate 'System.Converter<T,string>'
):
class A<T> {
void Method(T obj) {
Converter<T, string> toString = Convert.ToString;
// this doesn't work either (on .NET 4):
Converter<object, string> toString2 = Convert.ToString;
Converter<T, string> toString3 = toString2;
}
}
however, this does:
class A<T> {
void Me开发者_Go百科thod(T obj) {
// o is a T, and Convert.ToString(o) is using
// string Convert.ToString(object o)
Converter<T, string> toString = o => Convert.ToString(o);
}
}
In c# 4, co/contra-variant delegates can be assigned to each other, and delegates can be created from co/contra-variant methods, so the ToString(object)
method can be used as a Converter<T, string>
, as T
is always guarenteed to be convertable to an object
.
So, the first example (method group overload resolution) should be finding the only applicable method string Convert.ToString(object o)
, the same as the method call overload resolution. Why is the method group & method call overload resolution producing different results?
This has to do with the fact that variance is not applicable to value types, so if you restrict T
like where T : class
you get variance on T
and the first snippet of code will compile.
From the Covariance and Contravariance FAQ:
Variance is supported only if a type parameter is a reference type. Variance is not supported for value types.
The second code compiles because o
derives from object
, so obviously you can invoke a method that takes an object
as input with any type of parameter.
The delegate types, however, are not equal. Unless T
is object
the method signatures don't match. If, say, T
is int
you would have a Converter<int, string>
which is not the same as Converter<object, string
. They are two entirely different types.
You are hitting the issues around C# 3.0's lack of co/contra-variance. Should be better in C# 4.
精彩评论