One of my favorite features of C# 3.0 is the extension method. An extension method basically allows you to add a method to a class without altering the class itself. All you need to do is declare some static methods with a “this” keyword in the parameters. .Net will then add this method on to whatever class you indicate is a parameter of the method (immediately following the “this” keyword). Then, as long as you have included the namespace in your using declarations in the code file, you are all set. Some examples would probably help. Here are some sample declarations.
public static class MyExtensions { /// <summary> /// Validates (poorly) if an email address is in /// the right format. /// </summary> /// <param name="address">The email address to validate</param> /// <returns></returns> public static bool IsEmailAddress(this string address) { // Note: A purposely short pattern. Not suitable // for enterprise-level validation Regex regex = new Regex(@"^[\w-\.]+@([\w-]+\.)+[\w-]{2,4}$"); return regex.IsMatch(address); } /// <summary> /// Determines the future datetime, given the number /// of minutes to go forward. /// </summary> /// <param name="minutes">Number of Minutes to Add</param> /// <returns></returns> public static DateTime MinutesFromNow(this int minutes) { return System.DateTime.Now.AddMinutes(minutes); } /// <summary> /// Reverses the characters in a string. /// This method should have been included in the base library. /// </summary> /// <param name="input">The string to be reversed</param> /// <returns></returns> public static string Reverse(this string input) { char[] inputArray = input.ToCharArray(); Array.Reverse(inputArray); return new string(inputArray); } }
You can see that I’ve created three methods and added XML comments to them (so I get intellisense on those methods later). Looking at the Reverse method, I declare it just like a normal method, “public static string Reverse” but then in the arguments, I just add a “this” before I set the parameter. So, instead of just “string input”, I have “this string input”. This tells .Net to add this method as an extension on the string class.
You can see from this example that I see my Reverse method in a string’s intellisense as well as my comments for the method.
My total code to use each of my extension methods listed above is as follows.
static void Main() { Console.WriteLine("Reversed String: {0}", "PeteOnSoftwareRules!".Reverse()); Console.WriteLine("Now: {0}", System.DateTime.Now); Console.WriteLine("In 20 Mins: {0}", 20.MinutesFromNow()); Console.WriteLine("president@whitehouse.gov: {0}", "president@whitehouse.gov".IsEmailAddress()); Console.WriteLine("NotAnEmailAddress: {0}", "NotAnEmailAddress".IsEmailAddress()); }
When I run the code, I get the following results.
Good so far, but for now it seems like I am just changing how you would write some validation methods. Instead of IsEmailAddress(“a@b.com”), I am suggesting you write “a@b.com”.IsEmailAddress(). That is true so far. You could also create your own type that inherits from string and add a method, but then everyone else would have to use your type instead of the built-in .Net type. That’s not good at all. Additionally, extension methods add value by solving another problem.
Sometimes, you have to work with a framework or some third party class that has been sealed. I have for you the following example. It isn’t super useful, but concise, and will show my point 😉
public sealed class CannotInheritAndExtend { public string FirstName = string.Empty; public string LastName = string.Empty; public void PrintFirstName() { Console.WriteLine("First Name: {0}", this.FirstName); } }
I really need this class to write out the last name, also. With this example, it is impossible to say “public class WillInheritAndExtend : CannotInheritAndExtend” and then just add my own method. Go ahead and try. You will get a beautiful compiler error. What you can do, however, is the following:
public static void PrintLastName(this CannotInheritAndExtend input) { Console.WriteLine("Last Name: {0}", input.LastName); }
Now my method is included in intellisense for the original class.
So, now I can have this code
CannotInheritAndExtend a = new CannotInheritAndExtend(); a.FirstName = "pete"; a.LastName = "shearer"; a.PrintFirstName(); a.PrintLastName();
that produces the desired output.
As you can see, extension methods are really very helpful. They allow you to keep original types intact, but extend functionality onto them. I hope you find them as useful and cool as I do.