为什么list.Add(new B())
编译而list.Add(new Wrapper<B>())
无法编译?我认为要么编译要么两者都要编译,因为我认为编译器能够确定B
的隐式强制转换返回Wrapper<B>
,这是new Wrapper<B>()
生成的相同类型。我在VS 2012中使用C#4。
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>());
}
}
答案 0 :(得分: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
和{{{}}的用户定义隐式广播1}}扩展B
,并且存在从A
到A
的用户定义隐式广播。但是,根据规范(第6.4.4节详细here),您不能以这种方式将用户定义的隐式强制转换链接在一起。实际上,最小的例子甚至不需要处理泛型。考虑这个问题的简单例子:
Wrapper<A>
当然,如果你明确地进行了演员表,那么它可以工作:
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());
}
答案 1 :(得分:-2)
list.Add(new B());
不在列表中添加新的Wrapper<B>
。它在列表中添加了一个新的Wrapper<A>
。
编译器能够确定预期的类型是Wrapper<A>
,并且存在从new B()
到Wrapper<A>
的隐式转换,因为{{1}的操作数}需要接受Wrapper<A>
个对象,而A
是new B()
的一种类型。
A
不起作用,因为您不允许将list.Add(new Wrapper<B>());
添加到Wrapper<B>
,因为List<Wrapper<A>>
不是协变的。