Следующий код не компилирует (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;
}
}
однако, это делает:
class A<T> {
void Method(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);
}
}
В c# 4, co/contra-variant делегаты может быть присвоен друг другу, и делегаты могут быть созданы из co/contra-variant методов, таким образом, ToString(object)
метод может использоваться в качестве a Converter<T, string>
, как T
как всегда гарантируют, будет конвертируем к object
.
Так, первый пример (разрешение перегрузки группы метода) должен находить единственный применимый метод string Convert.ToString(object o)
, то же как разрешение перегрузки вызова метода. Почему группа метода и разрешение перегрузки вызова метода приводящий к различным результатам?
Это связано с тем, что дисперсия не применима к типам значений, поэтому если вы ограничите T
как where T : class
, то получите дисперсию на T
и первый фрагмент кода скомпилируется.
Из FAQ по ковариации и контравариации:
Вариация поддерживается только если тип является ссылочным типом. Вариация не поддерживается для значений типов.
Второй код компилируется, потому что o
является производным от объекта
, поэтому очевидно, что вы можете вызвать метод, который принимает объект
в качестве входных данных с помощью ] любой тип параметра .
Однако типы делегатов не равны . Если T
не является объектом
, сигнатуры методов не совпадают. Если, скажем, T
равно int
, у вас будет Converter
, который не совпадает с Converter
Вы столкнулись с проблемами, связанными с отсутствием в C # 3.0 согласованной / противоположной дисперсии. Должно быть лучше на C # 4.