Ошибка преобразования типа C # несмотря на общее ограничение
-
06-07-2019 - |
Вопрос
Почему, с общим ограничением на параметр типа T класса P, равным " должно наследоваться от A " ;, первый вызов завершается успешно, но второй вызов завершается с ошибкой преобразования типа, подробно описанной в разделе комментарий:
abstract class A { }
static class S
{
public static void DoFirst(A argument) { }
public static void DoSecond(ICollection<A> argument) { }
}
static class P<T>
where T : A, new()
{
static void Do()
{
S.DoFirst(new T()); // this call is OK
S.DoSecond(new List<T>()); // this call won't compile with:
/* cannot convert from 'System.Collections.Generic.List<T>'
to 'System.Collections.Generic.ICollection<A>' */
}
}
Разве общее ограничение не должно гарантировать, что List<T>
действительно действительно ICollection<A>
?
Решение
Это пример отсутствия в C # ковариации для универсальных типов (C # поддерживает ковариацию массива). C # 4 добавит эту функцию в типы интерфейсов, а также обновит несколько типов интерфейсов BCL для ее поддержки.
См. C # 4.0: Ковариация и контрвариация :
В этой статье я & # 8217; попробую осветить одну нововведений в C # 4.0. Один из новые функции ковариации и контравариантность параметров типа, теперь поддерживается общими делегатами и общие интерфейсы. Сначала позвольте & # 8217; s посмотрите, что означают эти слова:)
Другие советы
Ограничение не влияет на проблему; проблема в том, что вы передаете List в параметре, который требует ICollection - C # не поддерживает ковариацию, поэтому вам нужно явно привести список к ICollection:
S.DoSecond((ICollection<A>) new List<T>()); // this call will be happy
Вы строго ввели параметр для DoSecond как тип ICollection < A > ;. Несмотря на то, что T имеет тип A, во время компиляции неявное преобразование между List & Lt; T & Gt; и ICollection < A > ;. Вам нужно будет либо создать список и привести его к ICollection & Lt; A & Gt; когда вы вызываете DoSecond или делаете DoSecond самим универсальным методом. Р>
ПРИМЕЧАНИЕ. Этот тип неявного приведения должен поддерживаться в C # 4.0, что значительно улучшит совместимость / контравариантность по сравнению с тем, что предлагает C # 3.0.