More C# 3.0 – Extension Methods

Published 09 February 07 02:05 PM

A while back I wrote a post about lambda expressions in C# 3.0 and how they are one of the enabling technologies behind Linq. I would like to continue that discussion today with a quick overview of something called extension methods. First, I want to say up front that I believe extension methods are one of those features that will be useful for framework developers – but bring a very high risk of abuse if used widely in a general sense. So with that out of the way, I'll cover what extension methods are, how they can be used, and what are some of the "gotchas".

First, an extension method is simply a new technique for extending a class without inheriting from the class, making a partial class, etc… The really interesting thing about this technique is in the implementation details. In C# 3.0, extension methods are implemented by creating a static class (which implies that the methods will be static methods) and using the 'this' modifier on the first method parameter. For example, consider the following.

   1:  namespace LinqTestsHarness.Extensions { 
   2:    public static class TestExtensions { 
   3:      public static void SayHelloFromInt(this int arg) { 
   4:        Console.WriteLine("Hello " + arg.ToString()); 
   5:      } 
   6:    } 
   7:  }

As we have described, the extension method is identified by the fact that it is a static method (in a static class) and that it has the 'this' modifier on its first parameter. OK – so now we've go this extension method – what do we do with it? If you remember our working definition of an extension method from above, the method allows us to extend an existing type – and that's exactly what our new method does. For example, we can now run the following code.

using LinqTestsHarness.Extensions; 

... 

int n = 5; 

n.SayHelloFromInt(); 

And how did this work again? 2 things. First, we imported the namespace containing our extension method. Every time you import a namespace, you bring in every extension method that is defined within that namespace. The second important thing that allowed the above code to work is that we declared our variable (n) of type int – which is of course the type expected by our extension method. The following would not compile because of the type mismatch.

using LinqTestsHarness.Extensions; 

... 

string s = "howard"; 

n.SayHelloFromInt();

So by now you should have a pretty decent understanding of how extension methods work – so let's take a look at how they are used by Linq. Consider the following Linq expression.

IEnumerable<string> expr = from s in names 
  where s.Length == 5 
  orderby s 
  select s.ToUpper();

The Linq keyword such as 'where', 'orderby', etc… are simply shortcuts to extension methods defined in the System.Linq namespace. Therefore, the following is equivalent to the previous Linq expression.

IEnumerable<string> expr = names 
  .Where(s => s.Length == 5) 
  .OrderBy(s => s) 
  .Select(s => s.ToUpper());

So hopefully, you are now starting to see that Linq is not some sort of compiler magic. It is built on the very same language features that you have access to as you design and construct your solutions. Now, as we look at one potential application of extension methods, let me be quite clear that this is not a design pattern that I support – I am mentioning it here because I know that this is a pattern that many people do support, and if it is going to continue being used, extension methods are not a bad way to go about separating concerns. Let's consider object persistence. While there is significant debate over the "proper" architectural pattern for layer interactions, there is a school of thought that advocates the inclusion of persistence operations (Create, Read, Update, Delete) on business objects. One of the counter arguments to this approach is that you are then required to mix persistence code with business code and subsequently tie the business layer to a specific data access provider. In this context (let's forget about all of the other arguments both for and against this technique right now), extension methods provide a creative solution to the problem. For example, consider the following business entity class.

   1:  public class Person { 
   2:    private string _name; 
   3:    private int _age; 
   4:    private bool _canCode; 
   5:   
   6:    public Person() { } 
   7:   
   8:    public Person(string name) { 
   9:      Name = name; 
  10:    } 
  11:   
  12:    public Person(string name, int age) : this(name) { 
  13:      Age = age; 
  14:    } 
  15:   
  16:    public string Name { 
  17:      get { return _name; } 
  18:      set { _name = value; } 
  19:    } 
  20:   
  21:    public int Age { 
  22:      get { return _age; } 
  23:      set { _age = value; } 
  24:    } 
  25:   
  26:    public bool CanCode { 
  27:      get { return _canCode; } 
  28:      set { _canCode = value; } 
  29:    } 
  30:   
  31:    public override string ToString() { 
  32:      return Name; 
  33:    } 
  34:  }

If you wanted to maintain your data access code in a separate assembly, yet still have the appearance of data access methods on this class, you could create your data access class as a static class and use extension methods for the data access functionality. This extension class would look like the following.

namespace LinqTestsHarness.DataAccess { 
  public static class DataAccessExtensions { 
    public static void Save(this Person arg) { 
      // ... 
    }

    public static void Delete(this Person arg) { 
      // ... 
    } 
  } 
}

Just like in the previous case, using the extension method is a simple matter of importing the LinqTestsHarness.DataAccess namespace. The first parameter on the extension method constrains the method to only instances of the 'Person' class. Of course, all of the usual OO capabilities apply to extension methods. Were I using an ORM tool for my persistence, I could also create a marker interface and constrain the extension method to that interface rather than the concrete type. You can also create generic extension methods. However, my goal with this post is to simply give you an overview.

Now – a word of caution. While extension methods can be a very handy tool for allowing frameworks to add functionality to existing object models, they should probably be approached with a degree of caution. Like any cross-cutting technique, extension methods can be a real pain when it comes to tracing and debugging. One thing that you absolutely must keep in mind with extension methods is that they are given the lowest priority in terms of method invocation. Practically, this means that if the object instance already contains a method (virtual or otherwise) with the same name as your extension method, that method will always be give precedence over your extension method. Therefore, there's always going to be some degree of brittleness if you design a solution that makes heavy use of extension methods because your extension methods and the object model on which the methods are applied will probably evolve quite independently.

Secondly, and even more dangerous is the fact that although it appears as an instance methods, extension methods are of course static. What that means in IL terms is that extension methods use the 'call' instruction rather than the 'callvirt' instruction. Why is this important? Because the 'callvirt' instruction, the instruction called whenever you call an instance method on an object (in C#), checks for null and throws a 'NullReferenceException' if the object is null – the 'call' instruction does not. Therefore, the following code is perfectly legal.

Person howard = null; 
howard.Save();

Now, obviously, there are a lot of cool things that you can do with extension methods, and I'm not trying to say that you should never use them. Obviously, the Linq team has gained tremendous value from them. However, like with all things in development – just because you have a new hammer, don't turn everything into a nail!

Comment Notification

If you would like to receive an email when updates are made to this post, please register here

Subscribe to this post's comments using RSS

Comments

# .Net Adventures said on February 11, 2007 5:08 PM:

Ohad's Weblog - IE7Pro - a must have add-in if you use IE7 ! Simple Living Simple Thinking - Zip and

# Milan said on April 16, 2008 7:21 AM:

Hi Howard,

Nice intro and connection of LINQ and extensions. I have one problem with extensions. I couldn't find a way to make an extension method that would change an instance value. i.e.

public static void AddThis(this int source, int val)

{

  source += val;

}

This method doesn't throw an exception when it is called, but it doesn't change a value either. Do you have a solution for this?

# hdierking said on April 16, 2008 11:05 AM:

Hi Milan - extension methods don't allow ref or out parameters.  Therefore, you can't do what you're trying to do for value types like int.  You can of course, change the state of reference types.  As an example, in the following 2 tests, the first test (which is the same as your code) will fail because i cannot be passed as a ref param.  The second test will pass because you are simply changing the state of a reference type.

[Test]

public void testExtensionMethod_ValueType() {

 var i = 5;

 i.AddMe(3);

 Assert.AreEqual(8, i);

}

[Test]

public void testExtensionMethod_RefType() {

 var howard = new Person {Name = "Howard"};

 howard.ChangeName("Howard Modified");

 Assert.AreEqual("Howard Modified", howard.Name);

}

# Milan said on April 17, 2008 6:34 AM:

Hi Howard.

I thought so, but was hoping that's not true :(

# Abel Braaksma said on July 14, 2008 9:39 AM:

Hi Howard,

Thanks for the insights in this article. What I'd hoped to see, however, is a (small) explanation of the obviousness of the extension methods being static and why it isn't possible to create an extension instance method (i.e. Int32.MyExtension()).

I'd understand that the method already being static means that it cannot be "more" static (über-static???). Or do I misunderstand something and is it perfectly possible to create instance method extensions?

Thanks again,

Abel

# hdierking said on July 15, 2008 11:52 PM:

Hi Abel - so in terms of the obviousness of extension methods being static, it's related to the next part of your question.

Extension methods are static because for many types that you would want to create them for, you don't have access to the source code that would enable you to create instance methods (e.g. - Int32).

That said, from a syntactic perspective, extension methods behave in the same manner as instance methods - enabling you to to call an Int32 extension method using the syntax you specified Int32::MyExtension

essentially, the 'this' argument modifier enables a an extension method (which is static) to behave like an instance method in the code that uses it.

So the short answer to your question is this - an extension method is absolutely a static method from the compiler's perspective.  However, the extension method syntax enables it to be used as if it were an instance method on the type specified for the 'this' argument.

hth

Leave a Comment

(required) 
(optional)
(required) 

  
Enter Code Here: Required

About hdierking

I am currently the Editor-in-Chief for MSDN Magazine. I joined Microsoft in 2006 as a product planner with the certification team at Microsoft Learning. Prior to that, I spent my career as a developer and later as an architect. My main technology passions include pretty much anything on language theory, agile development, and service-oriented architecture.
Page view tracker