RError.com

RError.com Logo RError.com Logo

RError.com Navigation

  • 主页

Mobile menu

Close
  • 主页
  • 系统&网络
    • 热门问题
    • 最新问题
    • 标签
  • Ubuntu
    • 热门问题
    • 最新问题
    • 标签
  • 帮助
主页 / 问题 / 609773
Accepted
rdorn
rdorn
Asked:2020-12-31 21:30:06 +0000 UTC2020-12-31 21:30:06 +0000 UTC 2020-12-31 21:30:06 +0000 UTC

通用还是非通用

  • 772

在讨论我对问题的回答时,有一个争议点。

假设我们有一个泛型类和其中的三个方法:

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"); 
    }
}

实际上,问题是具有泛型类类型参数的泛型方法是否是泛型方法?

c#
  • 2 2 个回答
  • 10 Views

2 个回答

  • Voted
  1. Best Answer
    Vadim Ovchinnikov
    2021-01-01T00:33:20Z2021-01-01T00:33:20Z

    不过,您猜对了,答案是非通用的。因为有泛型方法的定义,仅此而已。

    当一个方法有自己的 类型参数时,它被认为是通用的。如果它没有,那么它就是一个非泛型方法。

    从泛型类型中,方法可以为返回值和/或参数类型借用类型参数(不要将参数类型与类型参数混淆,尽管这种双关语肯定会造成混淆),但如果该方法没有自己的类型参数,那将不会使其成为通用的。

    而且您对生成的 IL 的研究与我的论点完全不矛盾。但我仍然不会将编程语言术语与实现细节混淆。我认为这是不正确的。


    抛出一个话题来思考:有时非虚拟方法被称为 virtual。callvirt在某些情况下,只是为非虚拟方法生成一条指令,仅此而已。有人可能还会问“也许它们应该被称为隐式虚拟?” (但这里很明显,它只是为了实现)。


    开发者的尴尬

    但是对于新手(而且不仅仅是)开发人员来说,这至少在一开始是很奇怪的。例如,所有常用成员Dictionary都是非广义成员:Add(TKey, TValue)、ContainsKey(TKey)、TryGetValue(TKey, TValue)等Remove(TKey)。这让很多人感到惊讶,有时甚至是那些已经使用这本词典多年的人。类型是通用的,但方法不是。List情况很有趣:它只有一个 generic method ,其余的ConvertAll<TOutput>(Converter<T, TOutput>)没有。

    • 10
  2. rdorn
    2020-12-31T21:30:06Z2020-12-31T21:30:06Z

    MSDN将此类方法称为泛型类的非泛型方法,这并不比我在问题中的措辞好。在规范中,这个选项也没有单独考虑。好吧,既然什么地方都没有专门写,那我们就问问CLR本身吧,最后是她来执行我们写的所有东西。

    所以让我们从类声明开始

    .class public auto ansi beforefieldinit ConsoleApplication.SomeClass`1<T>
    

    一个有趣的点:`1——撇号后面的数字表示类型参数的个数,但这个增加的主要目的是为了扩展类名。因此,我们可以有两个具有相同名称和不同数量的泛型参数的类,包括一个没有参数的非泛型类。

    方法声明(我省略了主体,因为在这种情况下它并不重要):

    不是通用方法

    .method public hidebysig 
        instance void DoSomething (
            int32 x //тип указан явно
        ) cil managed 
    

    显式泛型方法

    .method public hidebysig 
        instance void DoSomething<U> (
            !!U x //обратите внимание на два восклицательных знака
        ) cil managed 
    

    两个感叹号告诉 JIT 在方法的泛型参数中查找特定类型。

    具有泛型类类型参数的非泛型方法

    .method public hidebysig 
        instance void DoSomething (
            !T x //тут только один восклицательный знак
        ) cil managed 
    

    单个感叹号告诉 JIT 在泛型类参数中查找特定类型。

    好了,东西已经有了,现在让我们看看这些方法是如何调用的:

    不是通用方法

    call instance void class ConsoleApplication.SomeClass`1<int32>::DoSomething(int32)
    

    明确指定参数类型

    显式泛型方法

    call instance void class ConsoleApplication.SomeClass`1<int32>::DoSomething<int32>(!!0)
    

    参数类型由对泛型方法参数列表中索引为 0 的参数的引用指示

    具有泛型类类型参数的非泛型方法

    call instance void class ConsoleApplication.SomeClass`1<int32>::DoSomething(!0)
    

    参数的类型由对泛型类参数列表中索引为 0 的参数的引用指示

    事实证明,在当前的实现中,我们有两种类型的泛型方法——显式和隐式。在这两种情况下,JIT 在编译这些方法以解析类型时都需要额外的步骤。在这两种情况下,调用时,仅指定对泛化参数列表中元素的引用。

    特定编译器/JIT/VM 实现的总计:

    1. 有两种类型的方法 - generic和non-generic。

    2. 泛型方法可以显式或隐式泛型化。

    3. 选择重载方法时的优先级,其他条件相同:

      • 没有一概而论
      • 隐式概括
      • 明确概括

    你可以在规范中找到这些信息,但只是间接的,没有直接的参考,显然它们依赖于读者的逻辑。


    PS:如果还有其他解释,我很乐意在您的回答中阅读。

    • 7

相关问题

Sidebar

Stats

  • 问题 10021
  • Answers 30001
  • 最佳答案 8000
  • 用户 6900
  • 常问
  • 回答
  • Marko Smith

    如何停止编写糟糕的代码?

    • 3 个回答
  • Marko Smith

    onCreateView 方法重构

    • 1 个回答
  • Marko Smith

    通用还是非通用

    • 2 个回答
  • Marko Smith

    如何访问 jQuery 中的列

    • 1 个回答
  • Marko Smith

    *.tga 文件的组重命名(3620 个)

    • 1 个回答
  • Marko Smith

    内存分配列表C#

    • 1 个回答
  • Marko Smith

    常规赛适度贪婪

    • 1 个回答
  • Marko Smith

    如何制作自己的自动完成/自动更正?

    • 1 个回答
  • Marko Smith

    选择斐波那契数列

    • 2 个回答
  • Marko Smith

    所有 API 版本中的通用权限代码

    • 2 个回答
  • Martin Hope
    jfs *(星号)和 ** 双星号在 Python 中是什么意思? 2020-11-23 05:07:40 +0000 UTC
  • Martin Hope
    hwak 哪个孩子调用了父母的静态方法?还是不可能完成的任务? 2020-11-18 16:30:55 +0000 UTC
  • Martin Hope
    Qwertiy 并变成3个无穷大 2020-11-06 07:15:57 +0000 UTC
  • Martin Hope
    koks_rs 什么是样板代码? 2020-10-27 15:43:19 +0000 UTC
  • Martin Hope
    user207618 Codegolf——组合选择算法的实现 2020-10-23 18:46:29 +0000 UTC
  • Martin Hope
    Sirop4ik 向 git 提交发布的正确方法是什么? 2020-10-05 00:02:00 +0000 UTC
  • Martin Hope
    Arch ArrayList 与 LinkedList 的区别? 2020-09-20 02:42:49 +0000 UTC
  • Martin Hope
    iluxa1810 哪个更正确使用:if () 或 try-catch? 2020-08-23 18:56:13 +0000 UTC
  • Martin Hope
    faoxis 为什么在这么多示例中函数都称为 foo? 2020-08-15 04:42:49 +0000 UTC
  • Martin Hope
    Pavel Mayorov 如何从事件或回调函数中返回值?或者至少等他们完成。 2020-08-11 16:49:28 +0000 UTC

热门标签

javascript python java php c# c++ html android jquery mysql

Explore

  • 主页
  • 问题
    • 热门问题
    • 最新问题
  • 标签
  • 帮助

Footer

RError.com

关于我们

  • 关于我们
  • 联系我们

Legal Stuff

  • Privacy Policy

帮助

© 2023 RError.com All Rights Reserve   沪ICP备12040472号-5