【问题标题】:Why are extension methods only allowed in non-nested, non-generic static class?为什么扩展方法只允许在非嵌套、非泛型静态类中使用?
【发布时间】:2010-10-14 05:29:41
【问题描述】:

为什么只能在非嵌套、非泛型的静态类中使用扩展方法? 在嵌套的泛型静态类中考虑扩展方法没有用吗?

【问题讨论】:

    标签: c#


    【解决方案1】:

    为什么只能在非嵌套、非泛型静态类中使用扩展方法?

    正如 Pratik 指出的,我们面临的问题不是“为什么嵌套或泛型类中不允许允许扩展方法?”作为语言设计者,我们面临的问题是“为什么在嵌套类或泛型类中应该允许扩展方法?”

    除非某些实际用户需要证明该功能是合理的,否则我们不会承担设计、实施、测试、记录和维护该功能的可观成本。

    基本上,扩展方法旨在使 LINQ 工作。任何对 LINQ 工作没有贡献的东西都被删掉了。 LINQ 只需要静态、非泛型、非嵌套类中的扩展方法即可工作,这就是我们设计和实现的。

    如果您有一个场景,扩展方法在非静态、泛型或嵌套类中很有用,那么我很乐意看看这个场景。我们获得的真实场景越多,我们就越有可能以某种假设的未来语言制作一个有利于这些场景的功能。

    在嵌套的通用静态类中考虑扩展方法没用吗?

    不,考虑一下是个好主意。如果我们不考虑这一点,我们就会失职。我们仔细考虑了很长时间,并在此考虑的基础上决定,执行该功能的成本与所产生的收益相比是不合理的。

    【讨论】:

    • 可能我的问题本质上是这个问题的一个副本,它提供了一个真实世界的例子(?)...stackoverflow.com/questions/11443842/…
    • IMO 这是一个非常短视的选择。或者选择被误导,不允许我直接在普通 C# 类中声明扩展方法。有很多次我想要 foo.ToBar() 扩展方法的本地用法,这在类之外没有相关性。
    • @EricLippert 感谢您的明确解释。添加到“真实世界用例”列表:我们列举了来自第三方来源的值。对于每个第三方源,我们在相应的适配器类中都有私有枚举来处理该源(对我们的应用程序的其余部分隐藏细节)。在外部,应用程序对这些值使用不同的、一致的 Enum。因此,在这些适配器类中,实现私有扩展方法以在枚举之间进行转换会很有用。
    • 扩展方法在顶级类中的限制意味着唯一可能受益于实例样式语法糖的静态方法是那些可以而且应该是公共的(因此不能使用任何私有类型)。也许声明这种公共方法的能力是定义扩展方法背后的驱动力,但这并不意味着公共方法是唯一有用的场景。能够让私有扩展方法使用私有类型也很有用。
    • 这是一个很好的例子,我需要这个功能。因为我想用扩展方法制作一个流畅的接口,并且我希望这些扩展方法只在给定的类中可用。
    【解决方案2】:

    正如 Eric Lippert 在他的博客中多次写的那样,对 C# 的每次更改都会根据一组标准进行仔细评估,以证明其合理性,而不仅仅是基于技术原因。在这种情况下,为了降低风险,不需要启用 LINQ 的内容被切断。查看来自 Eric 的 blog post 以了解类似问题。

    【讨论】:

      【解决方案3】:

      我相信这样做是为了让编译器可以在合理的时间内定位/搜索扩展方法。此外,请注意编译器搜索扩展方法仅在文件范围内的命名空间集中 - 这也是出于类似的原因。

      如果您考虑通用静态类场景,编译器必须尝试为所有可能的类型组合实例化具体类型以匹配扩展方法。即使编译器可以很聪明地做到这一点,为调用扩展方法而实例化具体类型也可能会产生开发人员可能没有意识到的副作用。

      【讨论】:

      • 你仍然可以让它们在任何类的范围内,但是。即,嵌套静态类的扩展将在包装类的范围内;特别是即使包装类是非静态和通用的,这也没有问题。
      • 我以前听过这个论点(将扩展方法限制为非嵌套、非泛型静态类以加快它们的发现),但不再那么相信了:我怀疑这是可能的快速识别程序集中所有用ExtensionAttribute 修饰的静态方法,即通过扫描CustomAttribute CLI 元数据表(参见CLI specification (ECMA-335) 的第II.22.10 章)。
      猜你喜欢
      • 1970-01-01
      • 2017-06-27
      • 1970-01-01
      • 2023-03-10
      • 1970-01-01
      相关资源
      最近更新 更多