2

なぜlist.Add(new B())コンパイルしてコンパイルしlist.Add(new Wrapper<B>())ないのですか? の暗黙のキャストが aから生成されたものと同じ型をB返すことをコンパイラが理解できると思ったので、両方またはどちらもコンパイルしないと思いました。VS 2012 で C# 4 を使用しています。Wrapper<B>new Wrapper<B>()

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>());
    }
}
4

2 に答える 2

2

あなたの質問から、 のインスタンスをリストに追加すると、何らかの形でリストに追加される に暗黙的にキャストされるため、作品Bのリストに追加すると思われるようです。しかし、これは起こっていることではありません。実際、コンパイラは から に 1 ステップでキャストすることはできません。 Wrapper<A>BWrapper<B>Wrapper<B>Wrapper<A>

のインスタンスを作品Bのリストに追加する理由Wrapper<A>は、コンパイラが がB拡張し、 からへAのユーザー定義の暗黙のキャストがあることを認識するためです。 AWrapper<A>

toおよびextendsからのユーザー定義の暗黙のキャストがあり、 toからのユーザー定義の暗黙のキャストがあるためWrapper<B>、 のリストにa を追加することもできると考えるかもしれません。ただし、仕様によると、この方法でユーザー定義の暗黙的なキャストを連鎖させることはできません (セクション 6.4.4 詳細はこちら)。実際、最小限の例ではジェネリックを扱う必要さえありません。この問題の簡単な例を考えてみましょう:Wrapper<A>Wrapper<B>BBAAWrapper<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());
}

もちろん、キャストを明示的に行うと、次のように機能します。

public static void Main()
{
    C.Method((B)new A());
}
于 2013-05-29T15:14:21.817 に答える
-2

list.Add(new B());リストに新しいものを追加していません。Wrapper<B>リストに新しいWrapper<A>ものを追加しています。

コンパイラは、期待される型がであること、および aのオペランドがオブジェクトを受け入れる必要があり、 の型であるため、Wrapper<A>そこnew B()にあるものから a への暗黙的な変換があることを判断できます。Wrapper<A>Wrapper<A>Anew B() A

list.Add(new Wrapper<B>());は共変ではないため、 aに aを追加することが許可されていないため、機能しません。Wrapper<B>List<Wrapper<A>>List

于 2013-05-29T15:18:38.787 に答える