【发布时间】:2012-07-11 16:06:54
【问题描述】:
我曾认为 C# 中的泛型是这样实现的,即在运行时或编译时生成一个新的类/方法/what-have-you,当使用新的泛型类型时,类似于 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() 上使用“覆盖”而不是“新”,那么返回 0 将多态地覆盖对象中的 GetHashCode 方法,这不是真的,但根据我(以前)的理解对于 C# 泛型,这无关紧要,因为 T 的每个实例都将被替换为 Test,因此方法调用将静态(或在泛型解析时)被解析为“新”方法。
所以我的问题是这样的:泛型是如何在 C# 中实现的?我不知道 CIL 字节码,但我知道 Java 字节码,所以我了解面向对象的 CLI 语言是如何工作的等级。随意在该级别进行解释。
顺便说一句,我认为 C# 泛型是这样实现的,因为与 Java 的类型擦除系统相比,每个人都将 C# 中的泛型系统称为“真正的泛型”。
【问题讨论】:
-
有什么理由在这里转换为对象 'gen == ((object)testVar).GetHashCode()' ?
-
虽然它没有直接回答您的问题,但blogs.msdn.com/b/ericlippert/archive/2012/07/10/… 提供了一些关于泛型如何强制转换以及它们在 C# 中如何相互关联的有用信息。
-
@Yogendra 这样做会访问 Object.GetHashCode() 方法,而不是“新”方法 Test.GetHashCode()。这就是它返回不同值的原因(因为它完全运行不同的方法)。
标签: c# generics polymorphism overriding