Vitaly's WebLog
Software development, startups, marketing

Extension Methods - Extension or Confusion?

January 4, 2008

One of the controversial features introduced in C# 3.0 is Extension Methods. From the first sight it is very handy and elegant solution for many problems, but when you think more about it you may realize that it may introduce serious and hardly discoverable issues. This is the reason I decided to write comprehensive overview of Extension Methods feature. Again, it worth knowing about extension methods in detail not because it is somewhat outstanding, but because they should be used very carefully to avoid great problems.

Definition

Extension methods are used to "extend" functionality of an existing class. Extension method is defined separately from the class it is extending. Here are the main rules that define Extension Methods:

  • Extension methods can be defined on classes, structures and interfaces
  • The method is defined separately from the class it is extending. It should be defined as static and be in non-generic static class that is not nested.
  • Extension method should have an “instance parameter” defined. This is the first parameter in Extension method and that is preceded by this modifier. The instance parameter cannot be a pointer type and cannot have parameter modifiers (ref, out, etc..)

There is no restriction on the name of extension method. This means that you may have several extension method with the same name and even with the same name as of some instance method. Method to call is selected in the following order:

  1. Instance method
  2. Extension method within the same namespace
  3. Extension method outside the current namespace

 

Hopefully, Visual Studio provides visual clues on where you are going to use extension method. Look at the picture below - AsQueryable and Cast<> are extension methods, while others are instance methods.

EM-Distinguishing

Finally, extension methods are resolved at compile time.

Example

Lets assume you have a class Cat:

using System;

namespace ExtensionMethodsSamples
{
    public class Cat
    {
        public void Eat(object food)
        {
            //TODO: eat implementation
        }

        public void Jump()
        {
            //TODO: jump implementation
        }

    }
}

After some time you want to extend it with Dance method. To create is as extension method you declare it in a separate class as a static method in a following way:

using System;
using ExtensionMethodsSamples;

namespace CatExtension
{
    public static class CatExtension
    {
        public static void Dance(this Cat cat)
        {
            for (int i=0; i<10; i++)
                cat.Jump(); // dumb implementation, forgive me, cat
        }
    }
}

Note this keyword in parameter declaration. Also note that method is static and that it is defined in namespace CatExtension(name doesn't matter, just note that it is different from the one where Cat is defined).

Now you should import namespace where extension method is defined and cat gains ability to "dance". You can call now Dance method of the Cat class just like the usual instance method.

using System;
using CatExtension;

namespace ExtensionMethodsSamples
{
    class Program
    {
        static void Main(string[] args)
        {
            Cat c = new Cat();
            c.Dance();

        }
    }
}

Note that CatExtension namespace was imported in the above snippet.

So, do they really extend?

There are two fundamental ways to extend the functionality of a class, by using inheritance or by using delegation. Extension methods are rather the symbiosis of the both. That is, you define them in separate utility class and then they magically become accessible as instance members (staying utility class that you can use at the same time). However, despite they look like instance methods, they are not instance methods. I think of a extension method as of an util static method, that is made accessible more easily. All after all it ends being static method in a separate class, with all limitation of that (no access to protected members etc...).

Extension of a class is better that its modification (as OCP stands for). Using extension method you can add functionality to your class without modifying its source code, while making it look just like an instance method (what you cannot do with delegation). This is the bright side of Extension Methods. The dark side is that all what you gain is just syntactic sugar and it is very easy to misuse them.

Extension Methods also represent the Decorator design pattern

The new meaning of the using directive

Here is how the using directive is defined in MSDN:

The using directive has two uses:
To permit the use of types in a namespace so you do not have to qualify the use of a type in that namespace:
To create an alias for a namespace or a type.

What we have now is an adding of new meaning to the using directive. Previously it was optional and just added more comfort to you leaving the need to type namespaces each time. Now, each using statement in your code file can mean that it adds or changes behavior. This scares me a bit, because it may lead to confusing errors.

So, when and how to use Extension Methods?

The possible right uses of extension methods:

  • To provide extension to a library that cannot be extended in other way and on which you do not have access over.
  • To use with Interfaces. Interfaces cannot include behavior by default. But now you can add it with Extension Methods.

However, I would suggest not to use Extension Methods whenever it is possible. The advantages they add doesn't worth it. But if still want to, here are several advices how to safely use them:

  • Always define extension methods in a separate namespace. They do behave as global functions. In this case you will have more freedom to mitigate collisions.
  • Do not define other types in the same namespace. Using directive attains new meaning now, do not forget. You will not want to have your types orphaned when there is name collusion caused by the Extension Method in he same namespace. Of course, you will be able to access them using fully qualified namespace, but it is easier just to define them in another namespace.
  • Consider using naming pattern for namespaces and classes containing extension methods. Consider situation when you add your extension method to a class of some library you do not have control on and vendor of the library add the method with the same name in that class. You will find yourself in a very bad situation, because now method of the vendor will be executed, not yours. Adding prefix to all your extension methods will help to avoid such situation.

Conclusion

Pros

  • Intuitive way to call a method that is defined in separate class. Look at you Utility classes with bunch of static methods, you now can now access them more easily and intuitively.
  • You can have an implementation for an Interface now. That looks like an very powerful feature, although an incidental one and very controversial. Microsoft holds out from Multiple Inheritance in .Net, but with extension methods we receive some more freedom on that.
  • You are creating a library that extends some existing code base and for which it is sufficient to have static methods, then extension methods are just for you (Linq is a good example).

Cons

  • Extension methods reduce discoverability of code
  • Object and the extension method are versioned independently. You can be put in a trouble when vendor of a class you are extending on creates the method with the same name. The worst thing is that behavior of you code may change while you are notified about that anyhow.
  • Spoiled using directive. Now it gains the new meaning and everyone using C# should le-learn. Hey, MS do not forget to update your old help files. And isn't it a violation of the Open-Closed Principle :-)?

I do not think that that is the right name for this feature. It makes people think that this is cure of extension and there is no good protection from the misuse for the same time. It is just a a bit glue that Microsoft made to implement Linq. It should be used very sparingly and generally indicates bad design, so think twice before using Extension Methods.

I'm not sure was it possible to implement Linq without implementing so controversial feature or not. Anyway, if it is not, then the decision can be justified by having Linq(Linq is just great!). From the other side, if Microsoft decided to give this language feature to everyone, why they did not provide some protection from misuse? I did not check yet if there are code analysis rules yet, but they should definetely be added.


Comments

January 4. 2008 09:11

Trackback from DotNetKicks.com

Extension Methods - Extension or Confusion?

DotNetKicks.com

January 6. 2008 11:28

Great reflection on extension methods (EM).

I think you have the same problem with EM as with any other tool: in the wrong hands it can cause serious damage. I personally like extension methods as they come close to something that Ruby calls "Mix-Ins". That is extending a class with generic functionality without actually inheriting from it or even having the code. An example where usage of extension methods makes sense is described at http://sentinel101.wordpress.com/. Here you can see how Unit-Tests get much more readable by putting the assertions into extension methods.

As a rule of thumb I would say that extension methods make sense if you have a very generic, cross-cutting functionality to add to existing classes. If you use them for just one or two classes it is better to implement the functionality as normal methods in the classes itself.

Mike

Comments are closed