假设我们有一个泛型类和其中的三个方法:
class SomeClass<T>
{
//не обобщенный метод
public void DoSomething(int x)
{
Console.WriteLine("True non generic method");
}
//не обобщенный метод с параметром обобщенного типа класса
public void DoSomething(T x)
{
Console.WriteLine("Indirectly generic method");
}
//явно обобщенный метод
public void DoSomething<U>(U x)
{
Console.WriteLine("True generic method");
}
}
实际上,问题是具有泛型类类型参数的泛型方法是否是泛型方法?
不过,您猜对了,答案是非通用的。因为有泛型方法的定义,仅此而已。
当一个方法有自己的 类型参数时,它被认为是通用的。如果它没有,那么它就是一个非泛型方法。
从泛型类型中,方法可以为返回值和/或参数类型借用类型参数(不要将参数类型与类型参数混淆,尽管这种双关语肯定会造成混淆),但如果该方法没有自己的类型参数,那将不会使其成为通用的。
而且您对生成的 IL 的研究与我的论点完全不矛盾。但我仍然不会将编程语言术语与实现细节混淆。我认为这是不正确的。
抛出一个话题来思考:有时非虚拟方法被称为 virtual。
callvirt
在某些情况下,只是为非虚拟方法生成一条指令,仅此而已。有人可能还会问“也许它们应该被称为隐式虚拟?” (但这里很明显,它只是为了实现)。开发者的尴尬
但是对于新手(而且不仅仅是)开发人员来说,这至少在一开始是很奇怪的。例如,所有常用成员
Dictionary
都是非广义成员:Add(TKey, TValue)
、ContainsKey(TKey)
、TryGetValue(TKey, TValue)
等Remove(TKey)
。这让很多人感到惊讶,有时甚至是那些已经使用这本词典多年的人。类型是通用的,但方法不是。List
情况很有趣:它只有一个 generic method ,其余的ConvertAll<TOutput>(Converter<T, TOutput>)
没有。MSDN将此类方法称为泛型类的非泛型方法,这并不比我在问题中的措辞好。在规范中,这个选项也没有单独考虑。好吧,既然什么地方都没有专门写,那我们就问问CLR本身吧,最后是她来执行我们写的所有东西。
所以让我们从类声明开始
一个有趣的点:`1——撇号后面的数字表示类型参数的个数,但这个增加的主要目的是为了扩展类名。因此,我们可以有两个具有相同名称和不同数量的泛型参数的类,包括一个没有参数的非泛型类。
方法声明(我省略了主体,因为在这种情况下它并不重要):
不是通用方法
显式泛型方法
两个感叹号告诉 JIT 在方法的泛型参数中查找特定类型。
具有泛型类类型参数的非泛型方法
单个感叹号告诉 JIT 在泛型类参数中查找特定类型。
好了,东西已经有了,现在让我们看看这些方法是如何调用的:
不是通用方法
明确指定参数类型
显式泛型方法
参数类型由对泛型方法参数列表中索引为 0 的参数的引用指示
具有泛型类类型参数的非泛型方法
参数的类型由对泛型类参数列表中索引为 0 的参数的引用指示
事实证明,在当前的实现中,我们有两种类型的泛型方法——显式和隐式。在这两种情况下,JIT 在编译这些方法以解析类型时都需要额外的步骤。在这两种情况下,调用时,仅指定对泛化参数列表中元素的引用。
特定编译器/JIT/VM 实现的总计:
有两种类型的方法 - generic和non-generic。
泛型方法可以显式或隐式泛型化。
选择重载方法时的优先级,其他条件相同:
你可以在规范中找到这些信息,但只是间接的,没有直接的参考,显然它们依赖于读者的逻辑。
PS:如果还有其他解释,我很乐意在您的回答中阅读。