RError.com

RError.com Logo RError.com Logo

RError.com Navigation

  • 主页

Mobile menu

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

C# 中具有相同签名的方法

  • 772

假设有这样一个类。

public class SomeClass<T>
{
    public void DoSomething(int x)
    {
        Console.WriteLine("DoSomething(int x) called");
    }

    public void DoSomething(T x)
    {
        Console.WriteLine("DoSomething(T x) called");
    }
}

还有一段代码

var someObj = new SomeClass<int>(); 

我有两个问题。

1) 私有类型SomeClass<int>有两个具有相同签名的方法。那为什么编译器不骂他们呢?

2)说如果打电话

someObj.DoSomething(0);

这段代码写着“DoSomething(int x) called”。为什么使用整数参数而不是通用参数调用变体?

c#
  • 1 1 个回答
  • 10 Views

1 个回答

  • Voted
  1. Best Answer
    rdorn
    2020-12-30T08:32:11Z2020-12-30T08:32:11Z

    规范摘录(条款 7.5.3.2):

    ...
    如果参数类型序列 {P1, P2, …, PN} 和 {Q1, Q2, …, QN} 是等价的(即每个 Pi 都有到对应 Qi 的恒等式转换),以下平分规则按顺序应用,以确定更好的函数成员。

    • 如果MP 是非泛型方法而MQ 是泛型方法,则MP 优于MQ。
    ...

    在俄语中听起来像这样:

    如果参数序列相同,则适用以下选择最佳方法的规则:

    • 如果方法 Mp 不是通用的,而方法 Mq 是通用的,则 Mp 优于 Mq

    还有更多的 dropout 规则,但对于这种情况,其余规则不是必需的。

    好的,从发现腿长出来的地方,规范中详细说明了这种行为。它在实施中是什么样子的?让我们看一下编译后的代码并比较泛型和非泛型方法。我使用 ILSpy,但您可以使用任何熟悉的工具,如 ILDasm。

    // Methods
    .method public hidebysig 
        instance void DoSomething (
            int32 x
        ) cil managed 
    {
        // Method begins at RVA 0x205a
        // Code size 11 (0xb)
        .maxstack 8
    
        IL_0000: ldstr "DoSomething(int x) called"
        IL_0005: call void [mscorlib]System.Console::WriteLine(string)
        IL_000a: ret
    } // end of method SomeClass`1::DoSomething
    
    .method public hidebysig 
        instance void DoSomething (
            !T x
        ) cil managed 
    {
        // Method begins at RVA 0x2066
        // Code size 11 (0xb)
        .maxstack 8
    
        IL_0000: ldstr "DoSomething(T x) called"
        IL_0005: call void [mscorlib]System.Console::WriteLine(string)
        IL_000a: ret
    } // end of method SomeClass`1::DoSomething
    

    如您所见,泛型类方法的代码在编译后仍然是泛型的(注意!第二个方法中类型名称的前缀)。

    当被问及为什么选择以这种方式出现,而不是相反时,他们回答说。现在稍微介绍一下这种实施的可能原因和选择规则。可能,因为我不是这个规范的开发者,但是从一般逻辑可以得出一些结论。

    1. 在泛型方法中,您只能将语言特性应用于泛型类型变量。例如,除相等和不相等检查外,不能使用比较运算符,因为 我们不能保证它们是在调用泛型方法的类型中实现的。因此,如果有合适的非通用方法可用,则很可能通过使用特定类型的专门工具来更有效地实现它。

    2. 在调用泛型方法之前,编译器必须用真实类型替换泛型类型。使用非泛型方法时不需要这些操作,这意味着即使在微不足道的情况下,当方法的效率相同时,调用泛型方法的成本微不足道,但更高。

    事实证明,泛型方法会损失一点性能,但有什么回报呢?毕竟,我们有一个共同的根类型object,任何其他类型也可以归结为该类型。我是这样看的:

    1. 当使用泛型方法时,不使用类型转换,就像使用 的情况一样object,这是一个速度增益,特别是对于 ValueType 类型,因为 没有拳击。

    2. 使用泛型类型时,可以确定两个变量是否具有相同的泛型类型。那么它们的类型在执行期间也将是相同的,不像 type 的变量object,它可以包含任何东西,并且需要额外的检查来消除运行时的错误。

    3. 在使用泛型类型时,我们可以随心所欲地使用细化或限制,并显式指定:它是一个类还是结构,是否存在构造函数(目前只有默认构造函数),基类型,以及一个列表必须在类型中实现的接口,允许在特定的泛型方法或类中使用。与前一个选项一样,此选项object只能通过额外检查和增加所需代码量来实现。

    自然地,对于这个特定实现的真正原因,我可能是错误的。当然,优点和缺点的清单远非完整。但我认为这足以让您大致了解为什么泛型类型和与之相关的一切都是它们现在的样子,以及如何将它们用于预期目的并永久使用。


    PS:除了引用规范和IL代码之外的所有内容都是我个人的意见,如果你不同意,那么我们可以在聊天中讨论,或者你可以写下你自己对这个问题的回答并表达你的观点。

    特别感谢@Vadim Ovchinnikov对之前版本的批评。

    • 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