非泛型类中的C# 泛型方法具体指什么?

11
如果我有这样一个类:-
static class Foo {
   public static void Bar<T>(T item) { Console.WriteLine(item.ToString(); }
}

我知道在这个例子中使用T是不必要的,因为所有类型都有ToString()等方法-这只是一个人为的例子。我更感兴趣的是在引擎盖下面发生的事情,具体来说是以下内容:

Foo.Bar("Hello");
Foo.Bar(123);
Foo.Bar(new Employee("Isaac"));

我大致理解具象化,即如果您创建一个泛型类的不同类型,例如:

List<Int32>
List<String>
List<Employee>

等等编译时(或运行时)我们最终会得到三种实际的具体类型,每个泛型参数都有一个。在我的第一个例子中,方法调用是否也适用于这个规则,即我们仍然只有一个类Foo,但是有三个重载的Bar方法,分别为String,Int32和Employee?


在编译时(或运行时?)等等,我们最终会得到三种实际的具体类型,每个泛型参数指定一个。在运行时,这是C++模板和泛型之间最大的区别之一。 - Hamlet Hakobyan
是的 - 对不起,我知道这一点(即具象化与类型擦除的区别)- 我指的是在编译时我们是否知道我们是否需要所有三种类型,并且它们是否立即由CLR在运行时生成,还是它们是由CLR以惰性方式“根据需要”生成的。 - Isaac Abraham
好的,那很有道理!主要问题是,我们在一个类中是否会得到三个方法实例,还是其他什么? - Isaac Abraham
2
@IsaacAbraham 在哪个层面上?C#: 明显不行。IL: 不行,只有一个;JIT/AOT/机器码:可能,取决于组合方式(所有引用类型实现可以共享相同的字节码;值类型实现不能共享)。 - Marc Gravell
你说在你的例子中使用 T 是不必要的。但是有一个很好的理由:如果 T 是值类型,那么就不会出现装箱。这很好。因此,在没有 where T : something 约束的情况下,即使没有约束,使用 T 类型参数(而不仅仅是 object)也是有原因的。 - Jeppe Stig Nielsen
显示剩余2条评论
1个回答

3

这就是C++模板和C#泛型之间区别的所在。

C++中,每个使用不同类型的实例都会生成一个新的方法。而在C#中,方法中的代码只会被创建一次。当你使用intstringobject类型参数调用时,相同的代码运行。

因为C#泛型在编译时保持通用性,所以可以在编译后的库中公开,而无需重新编译。在C++中,您需要将原始模板包含在使用的代码中,以便可以编译新的副本。

简而言之,每个泛型方法只有一个已编译的方法。


2
“Compiled” 可能会变得棘手;在 IL 级别上是正确的;在 JIT 级别上,可能会有多个 “已编译” 的实现 - 因此它取决于 “已编译” 的确切含义。AOT 编译器通常会立即生成 “n” 种方法,用于 “n” 种不同的用途。 - Marc Gravell
2
好的 - 我更关注运行时的角度 - 听起来对于引用类型版本,你在运行时得到一个实例,而对于每个不同的值类型,你大概会得到一个实例? - Isaac Abraham

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接