7

メソッドのディスパッチがあいまいで、コンパイラ(.NET 4.0.30319)が呼び出すオーバーロードを選択する基準を誰かが説明できるかどうか疑問に思ったところです。

interface IfaceA
{

}

interface IfaceB<T>
{
    void Add(IfaceA a);
    T Add(T t);
}

class ConcreteA : IfaceA
{

}

class abstract BaseClassB<T> : IfaceB<T>
{
    public virtual T Add(T t) { ... }
    public virtual void Add(IfaceA a) { ... }
}

class ConcreteB : BaseClassB<IfaceA>
{
    // does not override one of the relevant methods
}

void code()  
{
    var concreteB = new ConcreteB();

    // it will call void Add(IfaceA a)
    concreteB.Add(new ConcreteA());
}

いずれにせよ、なぜコンパイラは私に警告しないのですか、それともなぜコンパイルするのですか?ご回答ありがとうございます。

4

3 に答える 3

2

これは、 C#4仕様のセクション7.5.3.2 (「より優れた関数メンバー」)のルールに従います。

まず(両方の方法が適用可能であることを確認した後)、引数タイプからパラメータータイプへの変換を確認する必要があります。この場合、引数が1つしかないため、かなり単純です。引数タイプからパラメータタイプへの変換はどちらもからConcreteAに変換されるため、どちらも「より良い」ものではありませんIfaceA。したがって、これを含む次の一連の基準に進みます。

それ以外の場合、MPにMQよりも具体的なパラメーターの種類がある場合は、MPの方がMQよりも優れています。{R1、R2、…、RN}および{S1、S2、…、SN}が、MPおよびMQのインスタンス化されていないおよび拡張されていないパラメータータイプを表すとします。MPのパラメータータイプは、各パラメーターについてRXがSXよりも具体的であり、少なくとも1つのパラメーターについて、RXがSXよりも具体的である場合(SXよりも具体的)、MQよりも具体的です。

  • タイプパラメータは、非タイプパラメータほど具体的ではありません。
  • ..。

したがって、変換は同様に良好ですが、タイプのパラメーターはタイプのパラメーターよりも具体的であるIfaceAため、(デリゲートを介してではなく)直接使用するオーバーロードは「より良い」と見なされます。IfaceAT

コンパイラにこの動作について警告させる方法はありません。これは通常の過負荷解決です。

于 2010-05-18T07:29:56.080 に答える
1

コンパイラが最も具体的なものを最初に選択するからです。

あなたがそのように呼ぶとどうなりますか:

void code()   
{ 
    var concreteB = new ConcreteB(); 

    IfaceA  x = concreteB.Add(new ConcreteA()); 
} 
于 2010-05-18T07:14:31.170 に答える
1

これは、 JonSkeetのBrainTeaserの「型推論a-go-go」をいくらか思い出させます。コンパイラを信頼したくない場合は、を呼び出してコンパイラを強制的に選択することをお勧めします。Add<ConcreteA>(new ConcreteA())

于 2010-05-18T07:27:30.200 に答える