扩展方法和源代码的前向兼容性
我想解决在未来开发中使用扩展方法和类接口放大的问题(现在是假设的,但将来可能是真实的)。
示例:
/* 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" */
我的问题是:有什么方法可以防止这种情况(我没有找到)?如果现在有办法防止它,有什么方法可以找到这样可能的问题吗?如果现在如何找到可能的问题,我是否应该禁止使用扩展方法?
谢谢。
编辑:
你的回答很有用。 我可以找到代码中使用扩展方法的位置吗?和/或我可以找到代码中使用实例方法但存在具有相同签名的扩展方法的位置吗?
I would like solve the problem (now hypothetical but propably real in future) of using extension methods and maginification of class interface in future development.
Example:
/* 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" */
My question is: Is there some way how to prevent this case (I didn't find them)? If is now way how to prevent it, is there some way how to find possible issues like this? If is now way how to find possible issues, should I forbid usage of extension methods?
Thanks.
EDIT:
Yours answer was usefull.
Can I found where in code are used extension methods? And/or can I found where in code are used instance methods but exists extension method with same signature?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(4)
看起来您所描述的是以下情况
MySpecialList
的 V1 中没有Reverse
方法,因此对Reverse
的所有调用都绑定到同名的扩展方法MySpecialList
获得了一个Reverse
方法,现在所有以前对扩展方法的绑定都绑定到实例方法。如果您想在实例/扩展方法形式中调用 Reverse,则无法阻止这种情况,因为这是设计的行为。如果实例方法至少与扩展方法版本一样好,则实例方法将始终优先于扩展方法。
100% 防止这种情况的唯一方法是将扩展方法作为静态方法调用。例如,
与新版本产品绑定到新方法的问题不仅仅限于扩展方法(尽管问题可能更糟)。您可以对类型执行许多操作来改变方法绑定受影响的方式,例如实现新接口、继承或添加新转换
It looks like what you are describing is the following situation
MySpecialList
has noReverse
method so all calls toReverse
bind to an extension method of the same nameMySpecialList
gains aReverse
method and now all previous bindings to the extension method bind to the instance method instead.If you want to call Reverse in the instance / extension method form there is no way to prevent this as it's the designed behavior. Instance methods will always be preferred over extension methods if they are at least as good as the extension method version.
The only way to 100% prevent this is to call extension methods as static methods. For example
This problem of binding to new methods with new version of the product is not just limited to extension methods (although the problem is likely a bit worse). There are many things you can do to a type to alter the way method binding would be affected such as implementing a new interface, inheriting or adding a new conversion
这就是我们编写单元测试的原因。
首先,编写扩展方法。准确地说出它们的名字。因此,有一天,如果扩展方法作为同名类上的真实方法实现,那么很有可能它会与您的扩展方法执行相同的操作,并且不会造成任何破坏。
其次,通过单元测试,您将很快看到什么出了问题,并追踪到它出了问题,因为扩展方法不再被调用,因为该类现在有一个具有该名称的自己的方法。鉴于此,您可以选择重命名方法,将扩展方法作为静态方法调用,或者重写代码以正确使用新方法。
And this is why we write unit tests.
First, write extension methods. Name them precisely. So that one day, IF an extension method is implemented as a real method on the class with the same name, there is a good chance, it does the same thing as your extension method, and nothing breaks.
Secondly, with unit tests, you'll quickly see what broke, and track down that it broke because an extension method is no longer being called, since the class now has a it's own method with that name. Given that, you can choose to rename your method, call your extension method as a static method, OR rewrite your code to properly use the new method.
保证这一点的唯一方法是为您的扩展方法指定唯一的名称。这可能很简单,只需在方法前加上您姓名缩写的前缀即可。我知道它看起来很难看,但 99.9% 的时间应该都能用。
The only way to guarantee this would be to give your extension methods unique names. This could be as simple as prefixing the method with your initials. It looks ugly I know, but should work 99.9% of the time.
在这个特定的实例中,我认为返回新的反向列表(而不是在适当的位置反转列表)的扩展方法首先不应该被称为“Reverse”,而应该是 getReversedList() 或类似的方法。
但是你的观点(关于无副作用的扩展方法无意中被引起副作用的本地方法取代)是有效的;命名约定可能是一个好方法,但是,是的,这是不要不加区别地使用扩展方法的原因(但不足以禁止它们)。
In this particular instance I'd argue that the extension method that returns a new, reversed list (rather than reversing the list in place) shouldn't be called "Reverse" in the first place, but should be getReversedList() or some such.
But your point (about side-effect free extension methods getting inadvertently replaced with side-effect inducing local methods) is valid; a naming convention is probably a good approach, but yes, this is a reason not to use extension methods indiscriminately (but not sufficient to ban them).