扩展方法和源代码的前向兼容性

时间:2010-03-17 16:18:39

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

我想在未来的开发中使用扩展方法和类接口的maginification解决问题(现在假设但未来可行)。

示例:

/* 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" */

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

感谢。

修改

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

4 个答案:

答案 0 :(得分:4)

看起来你所描述的是以下情况

  1. 在您的产品的V1 MySpecialList中没有Reverse方法,因此对Reverse的所有调用都绑定到同名的扩展方法
  2. 在您的产品的V2中MySpecialList获得Reverse方法,现在所有先前对扩展方法的绑定都绑定到实例方法。
  3. 如果要在实例/扩展方法表单中调用Reverse,则无法阻止此操作,因为它是设计行为。如果实例方法至少与扩展方法版本一样好,则它将始终优于扩展方法。

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

    ExtensionMethods.Reverse(list);
    

    使用新版本产品绑定到新方法的问题不仅限于扩展方法(尽管问题可能有点糟糕)。您可以对类型执行许多操作来改变方法绑定的影响方式,例如实现新接口,继承或添加新转换

答案 1 :(得分:2)

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

首先,编写扩展方法。准确地命名它们。所以,有一天,如果一个扩展方法被实现为具有相同名称的类的真实方法,那么很有可能,它与扩展方法完全相同,并且没有任何中断。

其次,通过单元测试,您可以快速查看已损坏的内容,并追踪它已损坏,因为不再调用扩展方法,因为该类现在拥有自己的具有该名称的方法。鉴于此,您可以选择重命名方法,将扩展方法作为静态方法调用,或者重写代码以正确使用新方法。

答案 2 :(得分:1)

保证这一点的唯一方法是为您的扩展方法提供唯一的名称。这可以像使用首字母为方法添加前缀一样简单。我知道它看起来很难看,但应该有99.9%的时间工作。

答案 3 :(得分:1)

在这个特定的实例中,我认为返回一个新的反向列表的扩展方法(而不是反转列表)不应该首先被称为“Reverse”,而应该是getReversedList()或者其他一些。

但是你的观点(关于无副作用的扩展方法无意中被副作用诱导本地方法取代)是有效的;命名约定可能是一种很好的方法,但是,这是不加滥用扩展方法的理由(但不足以禁止它们)。