3

継承階層では、次のジェネリック メソッドを実装しています。

public class Base
{
    public virtual T Foo<T>()
    {
        Console.WriteLine("Base");
        return default(T);
    }
}

public class Derived : Base
{
    public override T Foo<T>()
    {
        Console.WriteLine("Derived");
        return default(T);
    }
}

public class DerivedDerived : Derived
{
    public override T Foo<T>()
    {
        base.Foo<string>();
        return default(T);
    }
}

ここで重要な部分は、メソッドの実装で、特定の型 ( ) を持つ基本クラスDerivedDerivedのメソッドを呼び出していることです。string

これを Visual Studio (2012) または LinqPad でコンパイルし、次のステートメントを実行すると:

var x = new DerivedDerived().Foo<string>();

出力は私が直感的に期待するものです:

Derived

ただし、Xamarin Studio 4.0 で同じコードをコンパイルして実行すると (Windows または Mac、Windows では、.NET または Mono C# でコンパイルして実行しても問題ないようです)、出力は次のようになります。

Base

ここで正しい結果は何でしょうか?

C# 言語仕様 5.0の 7.6.8 項には、次のステートメントが含まれています。

base-access が仮想関数メンバー (メソッド、プロパティ、またはインデクサー) を参照する場合、実行時に呼び出す関数メンバーの決定 (§7.5.4) が変更されます。呼び出される関数メンバーは、B に関して関数メンバーの最も派生した実装 (§10.6.3) を見つけることによって決定されます (これの実行時型に関してではなく、非ベースアクセス)。したがって、仮想関数メンバーのオーバーライド内で、base-access を使用して関数メンバーの継承された実装を呼び出すことができます。base-access によって参照される関数メンバーが抽象である場合、バインド時エラーが発生します。

一見すると、ジェネリック メソッドの呼び出しで特定の型を適用して継承階層を短絡しない限り、最も派生した実装、つまりDerived.Fooから呼び出されると思いますか?DerivedDerived.Foo

4

1 に答える 1

1

正しい結果は次のとおりです。これは、仕様の記述方法から明らかです。

Derived

編集:仕様には次のように書かれています:

呼び出される関数メンバーは、B に関して関数メンバーの最も派生した実装 (§10.6.3) を見つけることによって決定されます (これの実行時型に関してではなく、非ベースアクセス)。

の基底クラスDerivedDerivedDerived. Foo<T>に関しての最も派生した実装Derivedは ですDerived.Foo<T>。ではなく、それが呼び出されるメソッドBase.Foo<T>です。

于 2013-10-18T19:43:13.137 に答える