Monday, April 15, 2013

Extension Methods

Extension methods in .NET are methods that can be attached to another class without changing that class. In .NET extending a class is not the same thing as inheriting from a class. Extension methods only serve as a syntax shortcut to add helper type methods to an existing type or class.

Using Extension Methods

In both C# and VB.NET you can write a static class with static members to create your own extension methods. Below is an example of an extension method called SplitByPipe that extends the system type String to support splitting the string by a pipe character.

   1:  public static class StringEx
   2:  {
   3:    public static string[] SplitByPipe(this String s)
   4:    {
   5:       return s.Split('|');
   6:    }
   7:  }
   1:  class Program
   2:  {
   3:    static void Main(string[] args)
   4:    {
   5:       string input = "string1|string2|string3";
   6:       var result = input.SplitByPipe();
   7:       Console.WriteLine(result[1]);
   8:    }
   9:  }

You can also extend generic methods. When you create a generic extension method you must add the type parameter, in this case T, to both the method name and the this parameter type name. See the below example:

   1:  public  class MyClass<T>
   2:  {
   3:    public T Value { get; set; }
   4:  }
   5:  public  static  class MyClassEx
   6:  {
   7:    public static void MyEx<T>(this MyClass<T> mc)
   8:    {
   9:       Console.WriteLine(mc.Value);
  10:    }
  11:  }


The this reserved word before the first parameter of the string is required. It tells the compiler what class you are extending. The this keyword must also be the first parameter in the parameters list . You can add other parameters to the function but they can not have a this proceeding them.

The class and the method must both be declared static. This is a strange case where you are actually calling a static method but you usually call it using the instance of a class. If you want to call it as a static and not as an instance method than you must call it using the static class. In this case you would call StringEx.SplitByPipe(input).

You can not override a base method using an extension method. Although the compiler will not give an error, it will not work. Methods declared in the actual class will always take precedence and the custom extension will be ignored. However, if you have an extension method with the same name as a base method but different parameters, the extension method will be called and not the base method. The method signature has to be unique not the actual method name.

You can only override methods. C# does not provide any functionality to extend properties. The only alternative is to use the naming convention using methods: getMyProperty(...) and setMyProperty(...). That will not provide actual property syntax but it is standard naming when you can not use properties.

Your extension method's namespace must be included in order to show up. Just including the namespace of the base class will not import the namespace of the extension method. Extension methods are often included in a seperate assembly so you would first add the external assembly as a reference and then add the using statements to your codebase.

Why Use Extension Methods

While extension methods are in no way required to make a good .NET application they are very useful when it comes to writing utility type functions on an existing framework or even within your own code base. It is usually not considered best practice to inherit off of common and built in types like String and Integer. Doing so can make your code less portable and non-standard.

It is also worth mentioning that some classes in C# are sealed so you can not extend them using inheritance and you would have to explicitly declare them as partial in order to add to the class using a partial.

When Should You NOT Use Extension Methods

Extension methods can help you to avoid incrimenting a version number on a assembly by allowing modification to your class outside of its actual library. MyLibrary.dll might contain the core functionality while MyLibraryEx.dll would include extensions to that library. This can make sense when the extensions are not required in the core library and they logically fit together. However, if your only goal is to avoid recompiling an assembly than it is not a good idea. Multiple libraries that do not go together will only serve to complicate your references and make it difficult during deployment and troubleshooting.

If you are generating code using t4 or other scripting languages than a partial is more appropriate. A partial will give you more power and flexibility when you control the actual base class.

Inheritance may be more appropriate if the functionality fits more into the actual core requirements of your software and are always required. For instance if you have an animal super class and both feline and canine sub classes than it would make more sense to use inheritance instead of implementing feline and canine extension methods.

As with any programming feature, it can be overused and abused. If more of your solution is extension methods than other types of code than you may be overusing them. Generally my solutions only have a few extension methods that are used when I think the core framework should have implemented something or when it just makes the program easier to read.

What About Before Extension Methods

Before extension methods plain old static classes were used and the programmer would just pass an instance of the class into the static method. These are often called helper methods or helper classes. Helper methods are still in use even with the introduction of extension methods.

More Tips

  • You can implement more than one extension method type in one class. It is possible to extend both String and Integer within the same static class.
  • There is no naming convention enforced by the compiler. Extension classes do not have to end with Ex and the file does not have to end with Ex either.


More Resources

C#/.NET Little Wonders: Extension Methods Demystified

Updated: Generics can be extended. I removed it from the limitations.

1 comment: