【问题标题】:When should extension methods be avoided?什么时候应该避免扩展方法?
【发布时间】:2011-03-12 12:55:40
【问题描述】:

在您开始向我指出重复项之前,只需知道我已经阅读了几乎所有关于 SO 的关于扩展方法的帖子。我只是想扮演魔鬼的拥护者一分钟,以考虑替代我的工作意见。

最近我在做一个项目,需要一种方法作为接口的基础。所以我建议我们写一个扩展方法,但它被击落了。说它增加了复杂性并且更难调试。

我当然争论并开始寻找所有精彩的帖子,这些帖子展示了为什么使用扩展方法的许多原因。不要忘记很多 .net 框架都使用它们。我们最终没有使用它,因为我被团队否决了。

但后来我开始思考,是否有时可以使用扩展方法但不应该使用?

我真的想不出来,但我想我会在这里发帖,看看是否有人能想到任何其他不应该使用它们的原因。

【问题讨论】:

  • @Luiscencio 感谢您的文章。它有点长,所以我会在几分钟内阅读并回帖。但它看起来像我想知道的东西。

标签: c# extension-methods


【解决方案1】:

扩展方法使您能够向现有类型“添加”方法,而无需创建新的派生类型、重新编译或以其他方式修改原始类型。

任何时候你破坏了该功能的意图和设计,我建议重新考虑使用扩展方法。我看到一些你不想使用扩展方法的情况:

1) 更改对象模型以允许扩展方法:您要在其上创建扩展的类是抽象类。这将要求您将每个继承的类都设为自己的扩展版本,或者从类中删除抽象。无论哪种方式,您都在更改对象模型以使用扩展方法。

2) 忘记Decorator Pattern 您为一个类创建的扩展方法的数量超过了三个。我发现使用装饰对象比使用扩展对象更容易组织/通信和维护域/对象模型。然而,反之亦然:如果一个装饰对象的方法少于四个,我会在我的项目中发现很多几乎“空”的对象。

3) 私有函数:私有函数用于修改(创建、删除等)对象,扩展方法用于使用该类型,就像结构一样。如果您发现扩展名被分配给该类型的另一个实例,那么它可能不应该在扩展名中。

【讨论】:

    【解决方案2】:

    我会说,当“它们不会使代码的意图更清晰”时,您应该避免使用它们。当然,某些代码(或编码风格)是否“更清晰”在人与人之间差异很大,所以这几乎没有用。 (我有一位老板说我们应该避免使用接口,因为它们使代码“太复杂且难以理解”)

    【讨论】:

    • 我只是想知道你怎么会遇到可能很糟糕的情况。我猜如果您将与类或接口本身无关的方法作为扩展方法,那将是其中一种情况。 p.s.你的老板听起来像个真正的 OOP 大师:P
    【解决方案3】:

    任何时候你有一个“普遍适用”到某个类型的对象的函数,不管它的状态如何,扩展方法都是一个不错的选择。

    例如,今天我在我们的代码库中添加了两个新的扩展方法:

    public static XElement ToXElement(this XmlElement element) { }
    
    public static XmlElement ToXmlElement(this XElement element) { }
    

    一般来说,这两者在它们扩展的类型上都是有效的,无论实例的状态或我们在哪里使用它。

    如果您的方法不符合该标准,则可能应该将其移至更接近特定情况始终为真或易于检查的上下文的辅助方法。

    例如,一位开发人员最近将其指定为扩展方法:

    public static bool ParseYesNoBool(this string input) { }
    

    这里有两个问题:首先,这将出现在应用程序中的所有字符串上,即使可能成为这种情况的候选字符串的数量非常少。所以我们打破了第一条规则,因为无论状态如何,它都没有用。同样,但其次,此功能的使用者仅限于单个解析器,用于连接到外部系统的特定连接器。因此,将特定于实现的功能推广到通用名称空间是没有意义的。这被降级为解析器中的辅助方法。

    就可读性和调试而言,这对于任何合理技能水平的开发人员来说都是不正确的。

    【讨论】:

    • 我曾与一个拥有庞大的对象扩展文件的人一起工作,大多数都是相当具体的。我几乎不得不开始参加愤怒管理课程......
    • 这两个很好的例子说明了何时应该使用和不应该使用它们。我见过类似的情况,其中对象特定的功能被添加到 clr 对象中。他们正在检查类型中的域对象特定规则,并且只想向类型添加扩展方法以使其更容易。我想我还有另一个问题要问,我会发布而不是尝试将其全部放在此评论中?另外,使其可搜索以供将来参考。
    • 所以我跳过了这个问题,只是在另一条评论中问:如果该逻辑只在几个命名空间的上下文中使用,那么将 ParseYesNoBool 提升为扩展方法会不会很糟糕?这听起来不对。基本上,想知道如果您有特定类型的特定于域的扩展方法会怎样。仅当您加载包含扩展方法的命名空间时才会使用它们,因此它不适用于字符串的所有用途。只是那些特定于该使用领域的。下列的?这就是为什么我没有写另一个问题。我说的不好?
    • 我觉得是的,因为这会引入不必要的复杂性,但同时会增加代码的可读性。只是觉得我需要第二个意见。
    • 如果你正确地使用了命名空间,所有的扩展方法都不应该在任何地方都可用。我对上下文特定的扩展没有任何问题,这些扩展只存在于它们相关的上下文中。
    【解决方案4】:

    框架设计指南部分关于扩展方法的This discussion 包含一些很好的建议。我认为您的方案的相关部分是:

    提供与接口的每个实现相关的辅助功能,前提是所述功能可以根据核心接口编写。

    如果您提议的用法没有通过该测试,那么它应该被击落。

    【讨论】:

    • 我会看看我是否可以挖掘场景并在此处发布修改后的解释。
    【解决方案5】:

    一般来说,如果您控制程序集的源代码并且添加该方法不会对现有代码造成任何重大更改(例如,如果没有通过扩展方法实现 LINQ,则情况会更好)只需添加一个正常的方法。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2018-06-26
      • 1970-01-01
      • 1970-01-01
      • 2019-08-05
      • 2016-05-20
      • 1970-01-01
      • 2010-12-06
      相关资源
      最近更新 更多