【问题标题】:Why must C# extension methods be defined in static classes? [duplicate]为什么必须在静态类中定义 C# 扩展方法? [复制]
【发布时间】:2011-08-23 15:49:53
【问题描述】:

我了解 C# 扩展方法必须是静态的。我不明白的是为什么这些扩展不能在非静态类或泛型类中定义?

更新:我对这个设计决定背后的原因很感兴趣。

【问题讨论】:

  • 我在问这个问题之前彻底搜索了静态类案例,但我没有找到你提到的答案。顺便说一句,这不是完全相同的问题,我的答案在那篇文章中没有找到。
  • 这与“为什么不可能在泛型静态类中声明扩展方法?”的确切重复。
  • 这不是重复的。而是所谓的双重问题中更具体的问题。

标签: c# static extension-methods language-design


【解决方案1】:

这更像是一个观察而不是一个答案,但是......

当您调用实例方法时,对您正在调用的对象的引用将作为方法调用中的第一个参数压入堆栈。第一个参数是“this”并且是隐式完成的。

当你定义一个扩展方法时,你明确定义一个“this”作为第一个参数。

如果您可以在同一个类中定义扩展方法实例方法,即定义具有相同名称的方法,并且实际上在“包含this"参数。

【讨论】:

  • 这是一个很好的观察,也是一个合理的观察。感谢分享。
  • 也许,除了恕我直言,该规则确实应该有一个很大的例外:应该允许类或结构定义对其自己类型的成员进行操作的扩展成员,并且在结构的情况下,“this”参数应该可以是值或引用。这样的扩展方法将允许不可变类类型在初始化方面表现得更像值类型,并允许在 struct mutators 上使用普通的“方法”语法,而不会有将它们应用于只读上下文的风险。
  • @supercat 如果你可以在一个类中定义一个扩展方法来作用于它自己,那它就不是扩展方法了吗?
  • @chibacity:我描述的方法与实例方法的行为有些不同。对于引用类型,可以在其编译时类型已知的空对象上调用它们(允许不可变引用类型的行为类似于具有有效默认值的值类型);对于值类型,可以将改变左侧操作数(禁止在只读上下文中使用)的方法与不改变左侧操作数的方法区分开来。如果你不称它们为“扩展方法”,你会用什么术语来描述它们并将它们与实例方法区分开来?
  • @supercat 也许我误解了你。扩展方法的全部目的是扩展现有类型而不改变它们,即通过“添加”方法。您建议将扩展方法添加到目标类型本身 - 这不是设计意图。
【解决方案2】:

看看这段 .NET C# 规范:

当方法的第一个参数包含 this 修饰符时, 方法被称为扩展方法。扩展方法只能 在非泛型、非嵌套的静态类中声明。首先 扩展方法的参数不能有任何修饰符 this,并且参数类型不能是指针类型。

还有来自Jon Skeet's answer的这个片段:

我不清楚为什么所有这些限制都是必要的 - 除了可能为了编译器(和语言规范)的简单性。一世 可以看到为什么将其限制为非泛型类型是有意义的,但我 不能立即明白为什么它们必须是非嵌套的和静态的。一世 怀疑如果您不这样做,它会使查找规则变得相当简单 不得不担心当前类型等中包含的类型,但我 敢说有可能。

【讨论】:

    【解决方案3】:

    因为规范是这样写的...现在他们以这种方式编写规范可能有充分的理由。

    不能在泛型类中声明它们的原因很明显:鉴于调用扩展方法的方式,您将在哪里指定类的类型参数?

    它必须是静态类的原因不太明显,但我认为这是有道理的。静态类的主要用例是将辅助方法组合在一起(例如PathDirectoryProtectedData...),扩展方法基本上是辅助方法。例如,能够创建EnumerableQueryable 的实例是没有意义的。

    【讨论】:

    • 我明白规范所说的。我很想知道为什么会做出这样的设计决定。
    • @Mehran,这正是我试图在回答中解释的内容......我没有重复规范所说的内容。
    • 公共扩展方法仅在顶级静态类中有意义,但规则可能允许在嵌套的私有或受保护类中声明扩展方法,但前提是此类方法只能在可见的地方可用。例如,类Foo<T> 的代码可能受益于能够定义一个使用Foo<T> 私有类型的扩展方法。这样的扩展方法知道使用什么T 没有问题,因为唯一可以看到它的代码将具有该类型可用。
    • @supercat 在没有“this”返回类型的情况下,扩展方法实际上是在可以继承的类上编写流畅接口的唯一方法。鉴于此,最好将扩展方法放在它们所操作的类中,这样它们就可以访问私有成员并允许所有类代码都放在一个位置。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2014-10-31
    • 2023-03-10
    • 1970-01-01
    相关资源
    最近更新 更多