私は、C# のジェネリックは、C++ テンプレート (これは私が実際に調べたことはなく、間違っている可能性が非常に高いため、喜んで訂正を受け入れます)。
しかし、私のコーディングでは、正確な反例を思いつきました:
static class Program {
static void Main()
{
Test testVar = new Test();
GenericTest<Test> genericTest = new GenericTest<Test>();
int gen = genericTest.Get(testVar);
RegularTest regTest = new RegularTest();
int reg = regTest.Get(testVar);
if (gen == ((object)testVar).GetHashCode())
{
Console.WriteLine("Got Object's hashcode from GenericTest!");
}
if (reg == testVar.GetHashCode())
{
Console.WriteLine("Got Test's hashcode from RegularTest!");
}
}
class Test
{
public new int GetHashCode()
{
return 0;
}
}
class GenericTest<T>
{
public int Get(T obj)
{
return obj.GetHashCode();
}
}
class RegularTest
{
public int Get(Test obj)
{
return obj.GetHashCode();
}
}
}
これらのコンソール行は両方とも出力されます。
これが発生する実際の理由は、Object.GetHashCode() への仮想呼び出しが Test.GetHashCode() に解決されないことです。これは、Test のメソッドがオーバーライドではなく新規としてマークされているためです。したがって、Test.GetHashCode() で「new」ではなく「override」を使用した場合、0 が返されるとオブジェクト内のメソッド GetHashCode がポリモーフィックにオーバーライドされ、これは正しくないことはわかっていますが、私の (以前の) 理解によるとT のすべてのインスタンスが Test に置き換えられ、メソッド呼び出しが静的に (またはジェネリック解決時に) 「新しい」メソッドに解決されるため、C# ジェネリックの場合は問題になりませんでした。
だから私の質問はこれです:ジェネリックは C# でどのように実装されていますか? CIL バイトコードはわかりませんが、Java バイトコードは知っているので、オブジェクト指向 CLI 言語が低レベルでどのように機能するかは理解しています。そのレベルで気軽に説明してください。
余談ですが、Java の型消去システムと比較して、誰もが C# のジェネリック システムを常に「True Generics」と呼んでいるため、C# のジェネリックはそのように実装されていると思いました。