4

与えられた:

class BaseClass
{
    public virtual void M(int x) 
    { 

    }
}

class Derived : BaseClass
{
    public override void M(int x)
    {
        base.M(x);
    }

    static void M(object x)
    {

    }

    static void Main()
    {
        var d = new Derived();
        d.M(0);
    }
}

エラー:

メンバー'Derived.M(object)'は、インスタンス参照ではアクセスできません。代わりにタイプ名で修飾してください

C#4.0仕様のセクション7.4(メンバールックアップ)を見ると、最初の箇条書きは次のようになっています。

タイプTのKタイプパラメータを持つ名前Nのメンバールックアップは、次のように処理されます。

[...]オーバーライド修飾子を含むメンバーは、[Nという名前のアクセス可能なメンバーの]セットから除外されます

Derived.Mこのことから、オーバーライドにはアクセスできなくなったと結論付けます。代わりに、コンパイラはを参照する必要がありますBaseClass.M

Derived.Mただし、これは、スタティックを追加すると突然コンパイルエラーが発生する理由を説明していません。コンパイラーは静的メンバーのみを認識できるよう Derived.Mになり、このメンバーは無効な呼び出しであると結論付けます。スタティックを削除するとDerived.M、コンパイルは成功します。

なぜこれが起こるのですか?

4

2 に答える 2

7

次の手順が実行されているように見えますが、これらが一緒になってコンパイラエラーの原因になっています。

  • ステップ1:7.4のパーツのため。引用したように、のインスタンスバージョンMは削除され、コンパイラには静的バージョンのみが残ります。静的パラメータのパラメータタイプはobject、と互換性がありintます。メソッド名も一致します。
  • ステップ2:一致するメソッド(正しい名前、互換性のあるパラメーター)が見つかったため、メンバーのルックアップが終了しました。継承チェーンを上る必要はありません。
  • ステップ3:メソッドがインスタンスメソッドであるか静的メソッドであるかがチェックされるのは今だけです。

これを証明する仕様の一文を実際に引用することはできませんが、§7.4(メンバールックアップ)も§3.5(アクセシビリティ)もインスタンスについて話していません。したがって、この事実は、実行時にまったくstatic考慮されていないと思います。メンバールックアップ。

§7.4の関連部分は次のようです。

タイプTのKタイプパラメータを持つ名前Nのメンバールックアップは、次のように処理されます。

  • 最初に、Nという名前のアクセス可能なメンバーのセットが決定されます。
    [...]
    このセットは、継承されたメンバーとオブジェクト内のNという名前のアクセス可能なメンバーを含むTのNという名前のすべてのアクセス可能な(§3.5)メンバーで構成されます。Tが構築型の場合、メンバーのセットは、§10.3.2で説明されているように型引数を代入することによって取得されます。オーバーライド修飾子を含むメンバーは、セットから除外されます。

私がこの部分を理解する方法は、上で説明したようなものです。インスタンスメソッドと静的メソッドの両方を返し、override修飾子があるため、インスタンスメソッドを削除します。
この時点では、静的メソッドのみが残っています。

これで終わります:

最後に、[...]、ルックアップの結果が決定
されます。セットにメソッドのみが含まれている場合、このメソッドのグループはルックアップの結果です。

したがって、結果は静的メソッドになります。

明らかに、この問題は、クラス階層があり、派生クラスの1つが同じ名前と互換性のあるパラメーターを持つ静的メソッドを宣言している状況でのみ発生します。

このような静的メソッドを既存のクラスに追加することは、単にクラスに何かを追加するだけでも重大な変更である場合です。

コンパイラエラーを解決する方法を知っていると確信していますが、完全な答えを得るために、それを述べ
ます。変数のコンパイル時の型として、基本クラスのいずれかを使用します。ランタイムタイプは引き続き派生タイプである可能性がありますが、それは問題ではありません。

BaseClass d          = new Derived();
// ^                         ^
// compile time type        runtime type
于 2013-02-21T16:10:10.327 に答える
4

ダニエルの答えは正しいです。関連するルールの簡単な要約は次のとおりです。

  • 派生クラスのメソッドは、派生クラスのメソッドよりも常に優れていると見なされます
  • オーバーライドするメソッドは、それらをオーバーライドするクラスではなく、最初にそれらを宣言するクラスのメソッドと見なされます
  • 受信者がインスタンスであり、メソッドが静的であるかどうかを確認する前に、どのメソッドが「最良」であるかを解決します。(また、ジェネリック型パラメーターの制約がチェックされる前。)

この最後のルールは少し奇妙ですが、それはある程度意味があります。この特定のルールの詳細については、ハードバウンドの注釈付きC#4仕様の290ページと291ページにある私のコメントとnikovのコメントを参照してください。

また、このルールがルールと交差する興味深いコーナーケースの分析についてはColor Color、を参照してください。

http://blogs.msdn.com/b/ericlippert/archive/2009/07/06/color-color.aspx

于 2013-02-21T18:37:39.850 に答える