10

次の場合、ポリモーフィズムが適切に機能しないように見えます。次の定義があります。

interface BaseInterface{}
interface NewInterface:BaseInterface{}
class NewClass:NewInterface{}

class GenericClass<T> where T:BaseInterface
{
    public string WhoIAm(T anObject)
    {
        return TestPolymorphism.CheckInterface(anObject);
    }
}

class ImplementedClass:GenericClass<NewInterface>{}

class TestPolymorphism
{
    public static string CheckInterface(BaseInterface anInterface)
    {
        return "BaseInterface";
    }

    public static string CheckInterface(NewInterface anInterface)
    {
        return "NewInterface";
    }
}

次に、私が呼び出すと:

NewClass nc = new NewClass();
ImplementedClass impClass = new ImplementedClass();
Console.WriteLine("The result is " + impClass.WhoIAm(nc));

「結果はBaseInterfaceです」があります

nc が BaseClass とNewClass
を実装しているため、「結果は NewInterface である」と期待していましたが 、結果として「NewClass」を取得する最良の方法は何でしょうか?

ありがとう

4

1 に答える 1

17

非仮想メソッド呼び出しは、ジェネリックの実現のコンパイル時では なく、ジェネリック自体のコンパイル時に解決されることに注意してください。

したがって、これ:

class GenericClass<T> where T:BaseInterface
{
    public string WhoIAm(T anObject)
    {
        return TestPolymorphism.CheckInterface(anObject);
    }
}

を受け取るオーバーロードに解決されます。これは、実際 BaseInterfaceの型に関係なく、それを制約したものであるためです。T

C# のジェネリックは、C++ のテンプレートとは異なります。C# ジェネリックでは、すべての参照型がジェネリックの同じコードを共有するため、コンパイル時にジェネリック型を同様に扱います。つまり、ジェネリックは実際に実現される前にコンパイルされるため、ジェネリック型のプレースホルダーを使用してジェネリック呼び出しをオーバーロードするコンパイル時は、ジェネリック型自体に指定した制約に従うことしかできません。

つまり、GenericClass<T>使用法が考慮される前にコンパイルされます (これは、C++ がテンプレートを行う方法とは大きく異なります。どちらの方法にも長所と短所があります)。したがって、制約のないジェネリックがある場合 (ちょうどT) はobject、オーバーロードの目的であると見なされます (大まかに言えば) が、制約のあるジェネリックがある場合 (たとえば) は、オーバーロードの目的であるwhere T : BaseInterfaceと見なされます。BaseInterface

この場合、次のようなものが表示されます。

public static bool UberEquals<T>(T left, T right) where T : class
{
    return left == right;
}

したがって、これを次の方法で呼び出した場合は、次のようになります。

var s1 = "ello";
var s2 = "Hello";

UberEquals<string>('H' + s1, s2);

Tis 型なので、 sオーバーロードstringを呼び出しますが、 を制約していないため、そうしません。したがって、コンパイル時に の最小公分母を想定し、代わりにsを使用します。string==Tobjectobject==

これを考える別の方法:

BaseInterface bi = new ImplementedClass();

var x = TestPolymorphism.CheckInterface(bi);

BaseInterfaceオーバーロードは実行時に動的に解決されるのではなく、コンパイル時に解決されるため、X は常に上記のように言います。ジェネリックと非常によく似ていますが、ジェネリックは実現される前にコンパイルされることに注意してください。そのため、オーバーロード解決の目的で制約する基本クラスまたはインターフェイスにのみ使用できます。

于 2012-05-30T19:51:30.920 に答える