将通用对象添加到列表时的编译错误

时间:2013-05-29 15:07:36

标签: c# generics compiler-errors implicit-cast

为什么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>());
    }
}

2 个答案:

答案 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,并且存在从AA的用户定义隐式广播。但是,根据规范(第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>>不是协变的。