Ошибка компиляции при добавлении универсального объекта в список
Почему list.Add(new B())
компилировать и list.Add(new Wrapper<B>())
не компилировать? Я думал, что или оба, или ни один не скомпилируют, потому что я думал, что компилятор сможет выяснить, что неявное приведение B
возвращает Wrapper<B>
который того же типа производится из new Wrapper<B>()
, Я использую C# 4 в VS 2012.
class Wrapper<T> where T : new()
{
public static implicit operator Wrapper<T>(T obj)
{
return new Wrapper<T>();
}
public static implicit operator T(Wrapper<T> obj)
{
return new T();
}
}
class A { }
class B : A { }
class MyClass
{
public static void Main(string[] args)
{
List<Wrapper<A>> list = new List<Wrapper<A>>();
//This line compiles and runs successfully
list.Add(new B());
//This line doesn't compile
list.Add(new Wrapper<B>());
}
}
2 ответа
Из вашего вопроса кажется, что вы думаете, что добавление экземпляра B
к списку Wrapper<A>
работает потому что B
неявно приведен к Wrapper<B>
, который как-то добавляется в список. Тем не менее, это не то, что происходит. На самом деле, компилятор не может приводить из Wrapper<B>
в Wrapper<A>
в один шаг.
Причина добавления экземпляра B
к списку Wrapper<A>
работает потому, что компилятор видит, что B
продолжается A
и что существует пользовательское неявное приведение от A
в Wrapper<A>
,
Вы можете подумать, что вы также можете добавить Wrapper<B>
к списку Wrapper<A>
потому что есть пользовательское неявное приведение из Wrapper<B>
в B
а также B
продолжается A
и есть пользовательское неявное приведение из A
в Wrapper<A>
, Тем не менее, вы не можете связать воедино определенные пользователем неявные приведения таким образом, в соответствии со спецификациями (подробности см. В разделе 6.4.4). На самом деле, минимальный пример не должен иметь дело даже с дженериками. Рассмотрим этот простой пример проблемы:
class A
{
public static implicit operator B(A a) { return default(B); }
}
class B
{
public static implicit operator C(B a) { return default(C); }
}
class C
{
public static void Method(C c) { }
}
public static void Main()
{
C.Method(new A());
}
Конечно, если вы явно выполняете приведение, это работает:
public static void Main()
{
C.Method((B)new A());
}
list.Add(new B());
не добавляет новый Wrapper<B>
к списку. Это добавление нового Wrapper<A>
к списку.
Компилятор может определить, что ожидаемый тип Wrapper<A>
и что есть неявное преобразование из того, что там new B()
к Wrapper<A>
потому что операнд для Wrapper<A>
должен принять A
объект и new B()
это тип A
,
list.Add(new Wrapper<B>());
не работает, потому что вы не можете добавить Wrapper<B>
к List<Wrapper<A>>
так как List
не является ковариантным.