【问题标题】:Extensions methods and forward compatibilty of source code源代码的扩展方法和前向兼容性
【发布时间】:2010-03-17 16:18:39
【问题描述】:

我想解决在未来开发中使用扩展方法和放大类接口的问题(现在是假设的,但将来可能是真实的)。

例子:

/* the code written in 17. March 2010 */
public class MySpecialList : IList<MySpecialClass> {
    // ... implementation
}
// ... somewhere elsewhere ...
MySpecialList list = GetMySpecialList(); // returns list of special classes
var reversedList = list.Reverse().ToList(); // .Reverse() is extension method
/* now the "list" is unchanged and "reveresedList" has same items in reversed order */

/* --- in future the interface of MySpecialList will be changed because of reason XYZ*/

/* the code written in some future */
public class MySpecialList : IList<MySpecialClass> {
    // ... implementation
    public MySpecialList Reverse() {
        // reverse order of items in this collection
        return this;
    }
}
// ... somewhere elsewhere ...
MySpecialList list = GetMySpecialList(); // returns list of special classes
var reversedList = list.Reverse().ToList(); // .Reverse() was extension method but now is instance method and do something else !
/* now the "list" is reversed order of items and "reveresedList" has same items lake in "list" */

我的问题是:有什么方法可以防止这种情况(我没有找到)?如果现在是如何防止它,有没有办法找到这样的可能问题?如果是现在如何找到可能的问题,我应该禁止使用扩展方法吗?

谢谢。

编辑:

你的回答很有用。 我可以找到代码中使用扩展方法的位置吗?和/或我能否找到代码中使用实例方法但存在具有相同签名的扩展方法的位置?

【问题讨论】:

    标签: c# .net extension-methods language-features


    【解决方案1】:

    您所描述的情况似乎是以下情况

    1. 在您的产品 V1 中,MySpecialList 没有 Reverse 方法,因此所有对 Reverse 的调用都绑定到同名的扩展方法
    2. 在您的产品的 V2 中,MySpecialList 获得了一个 Reverse 方法,现在所有之前绑定到扩展方法的绑定都改为绑定到实例方法。

    如果您想在实例/扩展方法表单中调用 Reverse,则无法阻止,因为这是设计的行为。如果实例方法至少与扩展方法版本一样好,则它们总是优先于扩展方法。

    100% 防止这种情况的唯一方法是将扩展方法调用为静态方法。例如

    ExtensionMethods.Reverse(list);
    

    用新版本的产品绑定到新方法的问题不仅限于扩展方法(尽管问题可能更糟一些)。您可以对类型做很多事情来改变方法绑定受到影响的方式,例如实现新接口、继承或添加新转换

    【讨论】:

    • 是的,我的意思是完全一样的情况。如果我理解正确,最正确的方法是使用静态方法等扩展方法而不使用扩展方法?如何在代码审查中发现,指定的代码没有使用扩展方法?
    • 我不认为 Jared 是在说调用扩展方法,就好像它们是普通的旧静态方法一样是正确的方法;他只是说这是完全避免您所描述的风险的唯一方法——但无论如何,这种风险确实不是完全可以避免的。
    【解决方案2】:

    这就是我们编写单元测试的原因。

    首先,编写扩展方法。准确地命名它们。所以有一天,如果一个扩展方法在同名的类上实现为一个真正的方法,很有可能它和你的扩展方法做同样的事情,并且没有任何中断。

    其次,通过单元测试,您将很快看到发生了什么问题,并追踪它是因为不再调用扩展方法而导致的,因为该类现在有一个具有该名称的自己的方法。鉴于此,您可以选择重命名方法、将扩展方法调用为静态方法,或者重写代码以正确使用新方法。

    【讨论】:

      【解决方案3】:

      保证这一点的唯一方法是为您的扩展方法提供唯一的名称。这可以像在方法前面加上您的姓名首字母一样简单。我知道它看起来很难看,但应该在 99.9% 的时间里都能正常工作。

      【讨论】:

      • 是的,它看起来很丑,但是 BCL/3rd 方组件的扩展方法呢?
      • @TcKs - 你不能监管每个人的代码。没有足够的时间。使用@Chad 的答案 - 编写单元测试,以显示扩展方法是否已被破坏代码的东西替换。
      【解决方案4】:

      在这个特定的例子中,我认为返回一个新的、反向列表(而不是原地反转列表)的扩展方法不应该首先被称为“Reverse”,而应该是 getReversedList()或类似的。

      但是您的观点(关于无副作用的扩展方法被无意中替换为引起副作用的本地方法)是有效的;命名约定可能是一个好方法,但是是的,这是不随意使用扩展方法的原因(但不足以禁止它们)。

      【讨论】:

        猜你喜欢
        • 2011-10-08
        • 2021-05-13
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2015-05-19
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多