Extension Methods are a very cool and very innovative idea, new in Visual Studio 2008 (.NET Framework 3.5), that allows programmers to add custom methods to data types (without creating a derived type) that can be called just as if they were programmed within the type itself.
Whether it’s a class, structure, interface, delegate, etc. it can be extended, without inheritance, enabling it to gain new functionality, without actually having to be updated itself.
Imagine being able to add new functionality to the String data type so that it could change the case of it’s contents to Proper Case, maybe something like String.ToProper(); or imagine being able to add new functionality to the Integer data type so that it could raise it’s contents to a specified power, maybe something like Integer.ToPower(2); or imagine being able to add new functionality to the DataTable data type so that when the Copy method is called, you could tell it exactly what columns of data you want copied, maybe something like DataTable.Copy(“Column1”, “Column2”), etc. With Extension methods it’s now possible! And one of the coolest things is, it’s easy.
There are a some rules to consider before actually diving into working with Extension Methods, and they are:
1. An Extension Method can only be a Sub Procedure or a Function, not a property, field or event.
2. An Extension Method must be marked with the <Extension()> attribute, located in the System.Runtime.CompilerServices namespace.
3. An Extension Method must have at least 1 parameter. This parameter is always the first parameter (when there are more than 1 parameter) that indicates the type that it is extending. Additionally, this parameter is used to pass in the instance (ByVal or ByRef) of the data type it is extending.
4. Extension Methods must be defined within a Module.
Ok, so are you ready to see how this works? Let’s go…
First, create a new Windows Forms project. Next, add a new Module to it, named “ExtensionMethods.” After the module has been added, Import the System.Runtime.CompilerServices namespace. Your Module should now look like this:
Now we’re ready to add an Extension Method. Let’s extend the String data type, and add a new method to it that will change it’s contents to Proper Case:
Remember that the Extension Method must be marked with <Extension()>, and the first parameter indicates what type is being extended.
Reminder: Not only does the first parameter indicate what type is being extended, it is also used to pass in the instance (ByVal or ByRef) of the data type it is extending.
Ok, so that’s one Extension Method. Let’s add another one, this time extending the Integer data type by adding a new method to it that will raise it’s value to the specified power:
Note that the return value is a Double. This is because the return value could be greater than an Integer, and the Math.Pow method returns a Double data type.
Let’s add one more Extension Method. This time we will extend the DataTable data type by adding a new Copy method that will copy the contents of the DataTable to a new DataTable using the specified column names.
Method Overloading: You may realize that the DataTable type already has a Copy() method that copies the contents of the DataTable to a new DataTable. By adding a new Copy method that takes a parameter array of column names, we will actually be overloading the Copy method. This is permissible, because it has a different (parameter) signature.
Complete ExtensionMethods Module Example
Now that we have our 3 Extension Methods in our new ExtensionMethods Module, let’s take a look at what the module looks like:
Testing it out…
Now that we have our Extension Methods defined, let’s test them out.
Go back to the form, add a button to it, then double-click the button to create the Button_Click event handler. Test out the Extension Methods following my example below:
In the background…
If you were to look into the background and find out how the compiler is calling the extension methods, you would find that the compiler simply calls the shared method of the module, and passes it the variable calling the method. So the compiler’s version below is equivalent to our example above, producing the exact same results:
This information is useful, because if you choose to, you can utilize this pattern for calling the ExtensionMethods. Additionally, in rare situations where ambiguity occurs, this pattern will resolve conflicts.
As mentioned, interfaces can be extended as well as classes, structures and delegates, etc. But extending interfaces is a little different, because instead of only defining the Extension Method, you have to actually implement it. And if you are familiar at all with interfaces, immediately you’ll realize that is quite a bit different than the nature of interface types, which do not provide implementation.
Let’s take a look at an example of an IMath interface, and a ToPower() Extension Method:
And surprisingly enough, here’s how this example can be used in code:
If you put the module containing your Extension Methods in a namespace, then you will need to import that namespace in order to be able to access the Extension Methods. That’s something to keep in mind, because if you try to access one of your Extension Methods through a type instance, and cannot find your Extension Method listed in Intellisense, that’s the reason.
Additionally, if you decide to create a library containing all of your Extension Methods, when you add it as a reference to another project, be sure to import the namespace as well.
Extension Methods allows custom methods to be added to data types. The custom methods can only be Sub Procedures or Function, not properties, fields or events; they must be placed in a module; they must be marked with the System.Runtime.CompilerServices.Extension attribute; and they must have at least 1 parameter (the first parameter) that indicates the type that is being extended.