views:

77

answers:

4

Hi,

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?

+1  A: 

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.

ChrisF
Yes it looks ugly, but what about extension methods from BCL/3rd party components?
TcKs
@TcKs - you can't police everybody's code. There isn't enough time. Go with @Chad's answer - write unit tests that will show you if the extension method has been replaced by something that breaks your code.
ChrisF
+4  A: 

It looks like what you are describing is the following situation

  1. In V1 of your product MySpecialList has no Reverse method so all calls to Reverse bind to an extension method of the same name
  2. In V2 of your product MySpecialList gains a Reverse 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

ExtensionMethods.Reverse(list);

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

JaredPar
Yes, I mean the exactly same situation.If I understand right, the most right way is using extensions methods like static methods and don't use extensions methods?How can I found in code review, the specified code has not using extension methods?
TcKs
I don't think Jared is saying that calling extension methods as if they were plain old static methods is the right way; he's just saying that's the only way to completely avoid the risk you are describing -- but that risk really isn't completely avoidable anyway.
JacobM
@JacobM correct.
JaredPar
+1  A: 

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).

JacobM
+2  A: 

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.

Chad