7

私の問題は、私のクラス/インターフェース階層のコードスニペットで最もよく説明されていると思います:

public interface ITransform<D> // or <in D> --> seems to make no difference here
{
    void Transform(D data);
}

interface ISelection {}
interface IValue : ISelection {}

public interface IEditor : ITransform<IValue> {}
public interface ISelector : IEditor, ITransform<ISelection> {}

class Value : IValue { ... }
class Editor : IEditor { ... }              // implements ITransform<IValue>
class Selector : Editor, ISelector { ... }  // implements ITransform<ISelection>

Value v = new Value();
Selector s1 = new Selector();
ISelector s2 = s1;

s1.Transform(v); // resolves to ITransform<ISelection> --> WHY?
s2.Transform(v); // resolves to ITransform<IValue>     --> OK

質問 1: 2 番目のケースのように に解決され、s1.Transform(v)解決されITransform<ISelection>ないのはなぜですか?ITransform<IValue>

質問 2:ITransform質問 1 では、 が であるかである<D>かに違いはないようです<in D><in D>しかし、私のクラス/インターフェース階層での使用に他に問題はありますか? どちらのISelector実装ITransform<IValue>ITransform<ISelection>. IValue継承するため、ここで反変性が問題を引き起こす可能性がありますISelectionか?

EDIT お知らせ: 現在、Silverlight 4 を使用していますが、これは一般的な C# の動作だと思います。

4

3 に答える 3

2

Selector クラスは ITransform インターフェイスを実装します。つまり、Transform(ISelection) を処理するコードを含める必要があります。クラスは Transform(IValue) も処理できますが、それは Editor クラスから継承されたメソッドのみです。

ISelection バリアントを選択する理由は、それが Selector クラスで明示的に宣言されているバリアントであるためです。Transform(IValue) を選択するには、基本クラス (Editor) からの呼び出しを処理することをコンパイラが想定する必要があります。

編集:C#仕様の背景。

上記のセクションで詳しく説明されているように、これらの各コンテキストは、候補関数メンバーのセットと引数のリストを独自の方法で定義します。たとえば、メソッド呼び出しの候補のセットにはオーバーライドとマークされたメソッドは含まれず (§7.4)、派生クラスのメソッドが適用可能な場合、基本クラスのメソッドは候補ではありません (§7.6.5.1)。

于 2012-03-02T10:11:40.133 に答える
0

Q1では、コンパイラが有効なオーバーロードを取得するために短い階層チェーンを探すためだと思います。S1でITransformを取得するには、さらに先に進む必要があります。

s1->Selector->ISelector->ITransform<Selector>
s1->Selector->Editor->IEditor->ITransform<IValue>
s1->Selector->ISelector->IEditor->ITransform<IValue>

確認するソースを探します。

于 2012-03-02T08:56:11.477 に答える
0

質問 1: s1.Transform(v) が解決されて 2 番目のケースのように 解決されITransform<ISelection> ないのはなぜですか?ITransform<IValue>

私にとって、これはに解決されSelector.Transform<ISelection>ます。同様に、それはセレクターだと言いました。セレクターには Transform という名前のパブリック メソッドがあり、ISelection を取ります。IValue は ISelection を拡張します。いつ ITransform に強制されますか? これが反変性を示しているとは思いません。暗黙の変換だと思います。

質問 2: 質問 1 では、ITransform が不変であるinか不変であるかに違いはないようです。

ジェネリック パラメーターを戻り値の型ではなくメソッド引数として使用するため、規則では、パラメーターが反変的に有効である必要があり、これにより、 が許可され、 がin許可されなくなりoutます。

public class Example
    {

        public interface ITransform<D> // or <in D> --> seems to make no difference here
        {
            void Transform(D data); //contravariant in ITranform<out D>.
            //D Transform(string input);  //covariance ok
        }

        public interface ISelection { }

        public interface IValue : ISelection { }

        public interface IEditor : ITransform<IValue> { }
        public interface ISelector : IEditor, ITransform<ISelection>
        {
            new void Transform(ISelection data);
        }

        class Value : IValue { }
        class Editor : IEditor
        {
            public void Transform(IValue data)
            {
                throw new NotImplementedException();
            }
        } 
        class Foo : Editor, ISelector
        {
            public void Transform(ISelection data)
            {
                throw new NotImplementedException();
            }
        }  

        public void Whatever()
        {
            Value v = new Value();
            Foo s1 = new Foo();
            IEditor s2 = s1;

            s1.Transform(v); // resolves to Foo.Tranform(ISelection)
            s2.Transform(v); // resolves to ITransform<IValue>     --> cast into IEditor, which sig says ITransform<IValue>

        }

      }
于 2012-03-02T10:45:38.983 に答える