1

C#でこれが間違っている理由を誰かに説明してもらえますか:

namespace NamespaceA
{
    public class ClassA<T1>
    {
        T1 mT1;
        public T1 Type1
        {
            get { return mT1; }
        }
    }

    public class IOForClassA
    {
        public interface ICanOutput
        {
            void OutputFunction();
        }

        public static void Output(ClassA<ICanOutput> aClassA_WithOutputCapabilities)
        {
            aClassA_WithOutputCapabilities.Type1.OutputFunction();
        }
    }
}

namespace NamespaceB
{
    public class ClassB
    {
        public class OutputableClassA : NamespaceA.IOForClassA.ICanOutput
        {
            public void OutputFunction()
            {
            }
        }
        public ClassB()
        {
            NamespaceA.ClassA<OutputableClassA> aOutputableA = new NamespaceA.ClassA<OutputableClassA>();
            NamespaceA.IOForClassA.Output(aOutputableA);
        }
    }
}

これにより、次のコンパイル エラーが発生します。

引数 1: 'NamespaceA.ClassA"<"NamespaceB.ClassB.OutputableClassA">" から NamespaceA.ClassA"<"NamespaceA.IOForClassA.ICanOutput">" に変換できません

...しかし、NamespaceB.ClassB.OutputableClassAはNameSpaceA.IoForClassA.ICanOutputを実装しているため、これが問題になる理由がわかりません...

ユーザーが希望する任意のタイプの ClassA を作成できるようにしようとしています。ただし、ClassA を「出力可能」にしたい場合は、テンプレート化された型で特定のインターフェイスを実装する必要があります。

4

3 に答える 3

2

あなたは共分散/反変性の問題にぶつかっています。基本的に、ジェネリック型をより派生型にすることができるのはインターフェイスのみであり、in / outキーワード(リンクされた記事で概説)を使用して明示的に指定されている場合に限ります。

コードを読むと、型を知らずにクラスの既知の名前付きメンバーを呼び出したいように見えます。これは、型制約の方が少し適している可能性があります。ただし、デザインを少し変更する必要があるかもしれません。

namespace NamespaceA
{
    public class ClassA<T1> where T1 : IOForClassA.ICanOutput
    {
        T1 mT1;
        public T1 Type1
        {
            get { return mT1; }
        }
    }

    public class IOForClassA
    {
        public interface ICanOutput
        {
            void OutputFunction();
        }

        public static void Output<T>(ClassA<T> aClassA_WithOutputCapabilities) where T : IOForClassA.ICanOutput
        {
            aClassA_WithOutputCapabilities.Type1.OutputFunction();
        }
    }
}

namespace NamespaceB
{
    public class ClassB
    {
        public class OutputableClassA : NamespaceA.IOForClassA.ICanOutput
        {
            public void OutputFunction()
            {
            }
        }
        public ClassB()
        {
            NamespaceA.ClassA<OutputableClassA> aOutputableA = new NamespaceA.ClassA<OutputableClassA>();
            NamespaceA.IOForClassA.Output(aOutputableA);
        }
    }
}
于 2013-02-08T04:26:10.440 に答える
0

OutputableClassAから導出されICanOutputます。ClassA<OutputableClassA>しかし、それも から派生したものというわけではありませんClassA<ICanOutput>。それがあなたのコードが機能していない理由です。

ジェネリックのリンク共分散と反分散が役立つ場合があります。

于 2013-02-08T04:33:12.453 に答える
0

@syazdani は、それが共分散の問題であることについては正しいです (そして、彼は役に立つ記事にリンクしています) が、彼の例では共分散を使用していません。Output彼の答えは正しいですが (メソッドに実際の型が必要な場合に備えて、実際の型を持ち込むという追加の利点があるため、おそらく好ましいと思われます)あなたがそれらを使用する可能性のあるその他の場合:

namespace NamespaceA
{
    public interface IClassA<out T1>
    {
        T1 Type1 { get; }
    }

    public class ClassA<T1> : IClassA<T1>
    {
        T1 mT1;
        public T1 Type1
        {
            get { return mT1; }
        }
    }

    public class IOForClassA
    {
        public interface ICanOutput
        {
            void OutputFunction();
        }

        public static void Output(IClassA<ICanOutput> aClassA_WithOutputCapabilities)
        {
            aClassA_WithOutputCapabilities.Type1.OutputFunction();
        }
    }
}

namespace NamespaceB
{
    public class ClassB
    {
        public class OutputableClassA : NamespaceA.IOForClassA.ICanOutput
        {
            public void OutputFunction()
            {
            }
        }
        public ClassB()
        {
            NamespaceA.ClassA<OutputableClassA> aOutputableA = new NamespaceA.ClassA<OutputableClassA>();
            NamespaceA.IOForClassA.Output(aOutputableA);
        }
    }
}
于 2013-02-09T05:59:36.030 に答える