The .NET Framework 3.5, which was released in 2007, introduced the concept of Extension Methods.
Extension methods allow us to add new methods to an existing class, without having to make any changes to the class or having to inherit from the class.
Extension methods allowed Microsoft developers to add a lot more functionality to existing classes in the .NET base class library. A good example is LINQ, which we’ll talk about another day.
When we create an extension method, we define a static (shared) method. But when we invoke the extension method, it will look like a method of the original class.
Please note that the extension method doesn’t need to be defined in the same assembly or namespace where the original class is defined.
Even though the extension method is invoked as if it was part of the class, it’s not really a method of the class. Remember, we’re actually defining a static method, which means we can’t access private members of the class, only public members.
Also, if you define an extension method with the same name as an existing method of the class, the original method would be invoked, not the extension method. But you will not get an error.
Now let’s look at an example.
Let’s say we have the following class defined, which we already use in one of our applications.
using System; using System.Collections.Generic; namespace Example.Business { public class Order { //properties public int ID { get; set; } public Customer Customer { get; set; } public IList<Product> Items { get; set; } //empty constructor public Order() { } public Decimal GetTotal() { Decimal total = 0; //loop through each item and add up foreach (Product item in Items) { total += item.Quantity * item.UnitPrice; } return total; } public void Save(String filename) { Console.WriteLine("Order saved to {0}", filename); } public void Print() { Console.WriteLine("Order printed"); } } public class Customer { //properties public int ID { get; set; } public String Name { get; set; } public String Address { get; set; } //empty constructor public Customer() { } //constructor with parameters public Customer(int id, String name, String address) { ID = id; Name = name; Address = address; } } public class Product { //properties public int ID { get; set; } public String Description { get; set; } public Decimal UnitPrice { get; set; } public int Quantity { get; set; } //empty constructor public Product() { } //constructor with parameters public Product(int id, String description, Decimal unitPrice, int quantity) { ID = id; Description = description; UnitPrice = unitPrice; Quantity = quantity; } } }
The class holds order information, and it has methods to obtain the order total, to print the order, and to save the order to a file.
Here’s some code using this class.
using System; using System.Collections.Generic; namespace Example { using Business; class Program { static void Main(string[] args) { //create order Order order = new Order(); order.Customer = new Customer(1001, "Oscar Martinez", "555 Test St"); order.Items = new List<product>(); order.Items.Add(new Product(101, "XBox Console", 249.90m, 1)); order.Items.Add(new Product(101, "XBox Controller", 39.90m, 2)); Console.WriteLine("Total: {0}", order.GetTotal()); order.Save("test.txt"); order.Print(); Console.Write("\n\nPress any key to exit..."); Console.ReadKey(); } } }
This is the output.
Image may be NSFW.
Clik here to view.
Now let’s say we need to create an interface with a vendor, and we need to create a web service. We’ll exchange order information in XML format.
We would like to re-use the Order class, and it would be very useful to have a method to serialize the class to XML.
Let’s create a couple of extension methods.
using System; using System.Text; namespace Example.Extensions { using Business; public static class OrderExtensions { public static String ToXml(this Order order) { StringBuilder str = new StringBuilder(); str.AppendFormat("<order id="\"{0}\"" total="\"{1}\"">\n", order.ID, order.GetTotal()); str.AppendFormat("\t<customer id="\"{0}\"" name="\"{1}\"">\n", order.Customer.ID, order.Customer.Name); str.Append("\t</customer>\n</order>"); return str.ToString(); } public static void ToXml(this Order order, out String xml) { xml = order.ToXml(); } } }
Take a look at the first parameter of both methods. The this keyword before the parameter’s type is what connects our static method to the Order class.
Here’s some code using the new methods.
using System; using System.Collections.Generic; namespace Example { using Business; using Extensions; class Program { static void Main(string[] args) { //create order Order order = new Order(); order.Customer = new Customer(1001, "Oscar Martinez", "555 Test St"); order.Items = new List<product>(); order.Items.Add(new Product(101, "XBox Console", 249.90m, 1)); order.Items.Add(new Product(101, "XBox Controller", 39.90m, 2)); String xml; order.ToXml(out xml); xml = order.ToXml(); Console.WriteLine(xml); Console.Write("\n\nPress any key to exit..."); Console.ReadKey(); } } }
The extension methods were defined in the Example.Extensions namespace, and as soon as we import this namespace, the new methods are available to us.
Even though we defined a method with one parameter and another method with two parameters, we ended up with a method with no parameters and another method with one parameter. This is because the first parameter is only used to connect the extension method to the Order class.
This is the output.
Image may be NSFW.
Clik here to view.
Please leave a comment if you have any question.