Extension Methods and Advanced Source Code Compatibility

I would like to solve the problem (currently hypothetical, but promising in the future) using methods for expanding and magizing the 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 a way to prevent this case (I did not find them)? If now a way, how to prevent it, is there a way to find possible problems like this? If now you can find possible problems, do you prohibit using extension methods?

Thanks.

EDIT:

Your answer was helpful. Can I find where extension methods are used in the code? And / or can I find where the instance methods are used in the code, but is there an extension method with the same signature?

+4
source share
4 answers

It seems that you are describing the following situation.

  • There is no Reverse method in V1 of your MySpecialList product, so all Reverse calls are associated with an extension method of the same name
  • In V2 of your MySpecialList product, the Reverse method is received, and now all previous bindings to the extension method are instead bound to the instance method.

If you want to call Reverse in the form of an instance / extension method, there is no way to prevent this, since this is the designed behavior. Instance methods will always be preferable to extension methods if they are at least as good as the version of the extension method.

The only way to prevent 100% is to call extension methods as static methods. for instance

 ExtensionMethods.Reverse(list); 

This problem of binding to new methods with the new version of the product is not limited only to extension methods (although the problem is probably a little worse). There are many things you can do for a type to change the method binding method, for example, introducing a new interface, inheritance, or adding a new transformation

+4
source

And that is why we write unit tests.

First write the extension methods. Name them for sure. So one day, if the extension method is implemented as a real method for a class with the same name, there is a good chance, it does the same as your extension method, and nothing breaks.

Secondly, with unit tests, you will quickly see what is broken, and track that it is broken, because the extension method is no longer called, since the class now has its own method with this name. Given this, you can rename your method, call your extension method as a static method, or rewrite the code to correctly use the new method.

+2
source

The only way to guarantee this is to give your extension methods unique names. It can be as simple as a method prefix with your initials. It looks ugly, I know, but should work 99.9% of the time.

+1
source

In this particular case, I would say that an extension method that returns a new, inverted list (rather than reversing the list in place) should not be called “reverse” in the first place, but there should be getReversedList () or some of them.

But your point of view (about methods for the free distribution of side effects that are accidentally replaced by a side effect that causes local methods) is valid; naming convention is probably a good approach, but yes, this is the reason not to use extension methods indiscriminately (but not enough to prohibit them).

+1
source

Source: https://habr.com/ru/post/1304377/


All Articles