DotNetCurry Logo

C# Extension Methods Demystified

Posted by: Pravinkumar Dabade , on 3/28/2014, in Category C#
Views: 35525
Abstract: This article demystifies the controversial yet powerful C# Extension Methods and demonstrates some cool examples of extending classes, interfaces, collection classes, enums and ASP.NET MVC and Web API frameworks using Extension Methods.

Extension Methods allow an existing type to be extended with new methods without changing the definition of the original small. Before diving into Extension Methods, I want to discuss some challenges we face while adding new functionality to existing API’s. Let’s assume I am creating a Console Application with a class called as Sales. We will define this class as a sealed class to prevent other classes from inheriting from it. Our class is defined as follows:

public sealed class Sales
{
    public double COGS { get; set; }
    public double Expenses { get; set; }
    public double ActualSales { get; set; }

    public double SalesNetProfit(double COGS, double Expense, double actualSales)
    {
        return actualSales - (COGS + Expense);
    }
}

Now at a later date, one of your team members decides that he/she would like to extend the functionality of Sales Class by adding a new method called as CalculateServiceTax. As a usual practice, we would inherit the class and build our functionality. But this is not possible as our class is a sealed class [Not Inheritable class]. Another way could be that your team member may request the owner of the Sales class to add an additional method for calculating service tax in it. Although this would do the job, there is a higher chance that this may break the compatibility of other modules and projects with this class. So in most cases, this request will be denied by the owner of this class.

This article is published from the DotNetCurry .NET Magazine – A Free High Quality Digital Magazine for .NET professionals published once every two months. Subscribe to this eMagazine for Free and get access to hundreds of free tutorials from experts

Take another instance where you are using a third party DLL in your project. In my console Application, I will use a hypothetical popular third party DLL called as GameHelperAPI. Now I am expecting that this DLL has a class with the TextExplode method in it, which I want to use. So I will first add a reference to this DLL in my project

gamehelper

When I create an instance of the class PrintTextHelper present in the GameHelperAPI DLL, I find that the TextExplode method is not available in the third party API! Alas, that’s not what I had expected as I thought this method is available in the class.

printblinktext

The question is can I extend the class PrintTextHelper from the GameHelperAPI to add the TextExplode method? It’s obvious that I do not have access to the source code of the third party API [not applicable in special cases]. So I cannot change the original type to add a new method. I will try and inherit the class only to find out that I cannot do it because the class has been declared as sealed by the third party provider.

These kinds of issues are frequently encountered in our development scenarios where we are restricted to extend types. Similarly the .NET Framework classes also have similar restrictions. So it this is a dead end?

In .NET 3.5, a new concept called Extension Methods was introduced. Extension methods allow you to add new methods or properties to an existing type like a class or structure [includes Custom APIs, Framework APIs and third party APIs] without inheriting or modifying these existing types directly.

In the Microsoft .NET framework, the most common extension methods can be found in LINQ which extends the System.Collections.IEnumerable / System.Collections.IEnumerable for query operators.

In this article we will use extension methods to extend –

  • LINQ Framework classes
  • Custom classes
  • Interfaces
  • Nested classes
  • ASP.NET MVC classes
  • Web API classes

We will also see how to declare extension methods in –

  • Standard Class Library
  • Portable class library

and use them in various scenarios like –

  • Using extension methods in different languages. For example extension methods declared in C# will be used in VB.NET.
  • Using Extension methods in Windows Store App
  • Using Extension methods in Silverlight Applications
  • Using Extension methods in standard .NET applications

 

Using Extension Methods in LINQ

Let’s kick start by directly using the existing Extension methods available in the LINQ framework. I have created a simple console application which is querying the Object collection. The customer class in the console application is declared as follows:

customercls

The main method and customers collection is as declared here:

loadcustomer

linqmain

Now filter the collection data using the where<> method, which is an extension method:

linqwhere

The .NET framework has made use of Extension method for extending the framework classes as we saw in our example.

Custom Extension Methods

We will now try creating our own custom Extension method. I have created a console application which we will use to test our custom Extension methods.

In the demonstration here, we will extend the existing DatTime type of .NET framework. To do so, we will add a class called as HealthcarePolicyExtensions and then add some Extension methods to it as shown below –

public static class HealthcarePolicyExtensions
{
public static int Age(this DateTime date, DateTime
birthDate)
{
int birthYear = birthDate.Year;
int currentYear = DateTime.Now.Year;
if (birthYear>=currentYear)
{
throw new Exception(“Please enter correct birth
date!!”);
}
else
{
return currentYear - birthYear - 1;
}
}


public static decimal ClaimPolicy(this DateTime date,
DateTime claimDate,decimal claimAmount=120000)
{
DateTime currentDate = DateTime.Now;
if (claimDate >= currentDate)
{
throw new Exception(“Please enter correct Claim
date!!”);
}
else
{
return claimAmount;
}
}
}

In the above class we are extending DateTime type with two methods –

  • Age()
  • ClaimPolicy()

When we create an extension method, we have to follow some basic rules as listed below –

  • Extension method are declared in a static class.
  • All the extension methods must be static.
  • The first parameter of the Extension method is a type which we want to extend, so it must be declared with this keyword.

We will now try to call our Custom extension methods in our main function. Observe how the DateTime class now has additional methods, as shown here –

static void Main(string[] args)
{
try
{
    Console.WriteLine("Enter your Birth Date");
    DateTime d = Convert.ToDateTime(Console.ReadLine());
    DateTime calculateAge = new DateTime();
    int age = calculateAge.Age(d);
    Console.WriteLine("Your Age is - {0}", age);
}
catch (Exception ex)
{
    Console.WriteLine(ex.Message);
}
Console.ReadKey();
}

The output of the program is as shown below –

datetimeoutput

Using extension methods, we can extend classes, structures, interfaces, collection classes etc.

Extending an Interface using Extension Methods

Let’s see how to extend an interface using Extension methods. We will declare a class called as “PurchasedProducts” as shown here –

public class PurchasedProduct
{
    public int ProductCode { get; set; }
    public string ProductName { get; set; }
}

Now declare an interface called as IProduct

public interface IProduct
{
    IEnumerable GetProducts();
}

The interface declares a method called as GetProducts which returns an IEnumerable of PurchasedProduct. Create two classes which will implement the IProduct class as shown here –

public class FoodProducts:IProduct
{
public IEnumerable GetProducts()
{
    return new List
    {
        new PurchasedProduct{ProductCode=2900,ProductName="Chai"},
        new PurchasedProduct{ProductCode=2901,ProductName="Coffee"},
        new PurchasedProduct{ProductCode=2902,ProductName="Milk"},
    };
}
}

public class ElectronicProducts : IProduct
{
public IEnumerable GetProducts()
{
    return new List
    {
        new PurchasedProduct{ProductCode=3000,ProductName="Oven"},
        new PurchasedProduct{ProductCode=3001,ProductName="Washing Machine"},
    };
}
}

We will add an Extension method to our interface IProduct as shown here –

public static class IProductExtensions
{
    public static IEnumerable GetProductByCode(this IProduct product,int proCode)
    {
        return product.GetProducts().Where(p => p.ProductCode == proCode);
    }
}

The IProductExtension class extends an interface IProduct which returns the product by passing the product code. Try using the interface extension method in our Main method –

static void Main(string[] args)
{
    try
    {
        IProduct product = null;
        product = new FoodProducts();
        Console.WriteLine("Total No. of Food Products - {0}", product.GetProducts().Count());
        Console.WriteLine("Food Product Name is {0}", (product.GetProductByCode(2900).SingleOrDefault()).ProductName);
        product = new ElectronicProducts();
        Console.WriteLine("Total No. of Electronic Products - {0}", product.GetProducts().Count());
        Console.WriteLine("Electronic Product Name is {0}", (product.GetProductByCode(3000).SingleOrDefault()).ProductName);

    }
    catch (Exception ex)
    {
        Console.WriteLine(ex.Message);
    }
    Console.ReadKey();
}

The output of the above program is as shown here -

interfaceextouput

Working with Private/Protected members of a Class

In some scenarios, while creating Extension methods you may need to access methods or data members which are not directly available outside the class. For example, Private/Protected members of the class which is being Extended. Let’s take a look at the following example –

public class DisplayMessage
{
    private DateTime _captureCurrentDate;
    public void SetTime()
    {
        _captureCurrentDate = DateTime.Now;
    }
    public string GetIndiaMessage()
    {
        if (_captureCurrentDate.Hour<12)
        {
            return "Good Morning!!";
        }
        else
        {
            return "Good Evening";
        }
    }
}

We will extend the DisplayMessage class by calling the private data member _captureCurrentDate into our Extension methods. In this scenario, we will have to read the value of the variable using Reflection. Here’s our Extension Method

public static class DisplayMessageExtensions
{
    public static string GetCountrySpecificMessage(this DisplayMessage message,string country)
    {
        var privateField = typeof(DisplayMessage).GetField("_captureCurrentDate", BindingFlags.Instance | BindingFlags.NonPublic);
        var currentDateTime = (DateTime)privateField.GetValue(message);
        if (country == "USA" && currentDateTime.Hour < 12)
        {
            return "Good Evening!!";
        }
        else
        {
            return "Good Morning";
        }
    }
}

Let’s make use of the Extension method we just created -

static void Main(string[] args)
{
    try
    {
        DisplayMessage displayMsg = new DisplayMessage();
        displayMsg.SetTime();
        Console.WriteLine("Message For Indian Time - {0}", displayMsg.GetIndiaMessage());
        Console.WriteLine("Message For USA Time - {0}", displayMsg.GetCountrySpecificMessage("USA"));
    }
    catch (Exception ex)
    {
        Console.WriteLine(ex.Message);
    }
    Console.ReadKey();
}

The output of the above program is as follows –

reflectionext

Extension Methods with Nested Classes

A Nested class is a class within a class. Nested classes by default are private, but can be made public, protected internal, protected or internal. Here’s a sample nested class –

public class ParentClass
{
    public string MessageFromParent()
    {
        return "This Message is from Parent!!";
    }
    private class ChildClass
    {
        public string MessageFromChild()
        {
            return "This Message is from Child!!";
        }
    }
}

In the code we have a ParentClass which has a nested class ChildClass declared as private. The question is how to add an Extension method to ChildClass? The answer is to use reflection to extend the nested child class and add an Extension method. The extended class is shown below –

public static class NestedClassExtensions
{
    public static string ToUpperCaseParentMessage(this ParentClass pObj)
    {
        return pObj.MessageFromParent().ToUpper();
    }

    public static string ToUpperCaseChildMessage(this object o)
    {
        var childUpper = string.Empty;
        var privateClass = typeof(ParentClass).GetNestedType("ChildClass", BindingFlags.NonPublic);
        if (o.GetType()==privateClass)
        {
            var callMethod = privateClass.GetMethod("MessageFromChild");
            childUpper = (callMethod.Invoke(o, null) as string).ToUpper();
        }
        return childUpper;
    }
}

In the NestedClassExtensions class, we are using reflection to add an Extension method to our private nested class. We will now use the nested class and access its Extension method in our Main method shown below –

static void Main(string[] args)
{
    try
    {
        ParentClass p = new ParentClass();
        Console.WriteLine(p.ToUpperCaseParentMessage());

        var privateClass = typeof(ParentClass).GetNestedType("ChildClass", BindingFlags.NonPublic);
        var c = Activator.CreateInstance(privateClass);
        var callMethod = privateClass.GetMethod("MessageFromChild");

        Console.WriteLine(callMethod.Invoke(c, null));
        Console.WriteLine(c.ToUpperCaseChildMessage());

    }
    catch (Exception ex)
    {
        Console.WriteLine(ex.Message);
    }
    Console.ReadKey();
}

The output of the program is shown here –

nestedclassext

The extension method is available under the scope of the namespace in which it is declared. If you want to use these Extension methods in another namespace, you will have to import the namespace.

Creating an Extension Methods library

You can also create a separate library of Extension methods which you can reuse into a number of applications as per your requirement. Let’s create a standard class library which we will use in various applications. I have added a class library to the project with the name “ExtensionStandardLibrary”. Write the following code in our class library –

public static class StringExtensions
{
    public static bool FindWord(this string s, string message, string wordToFind)
    {
        return Regex.IsMatch(message, wordToFind);
    }
}

So here we are extending the framework’s string type which will find a given word in a string. Now this is a very simple method which I would like to use in various applications. So let’s compile the library and try using it in a VB.NET console application.

Using a C# Extension Methods Library in a VB.NET application

Let’s add a VB.NET console application to test our C# Extension method library as shown here [Add a reference to the extension method library in our VB.NET application] –

Module Module1

Sub Main()
    Console.WriteLine("VB.NET Console Application")
    Dim msg As String = "WelCome To India. India is growing as a popular IT Market for major development companies"
    Dim res As String = msg.FindWord(msg, "IT")
    Console.WriteLine(res)
    Console.ReadKey()
End Sub

End Module

The output of this VB.NET program is shown here –

vboutput

Using the Extension Methods library in a Silverlight and Windows Store application

Now let’s make use of this Extension library in other applications. For example I would like to use this library in a Silverlight as well as Windows Store Application too. To do so, add the Extension library reference into our projects respectively. When we try adding a reference of the standard extension library, we get the following error –

slappreferror

Similarly try adding the library into a Windows Store App and by doing so, we will receive the following error –

winappstoreerror

An important point to remember here is that to make use of Extension methods as an library, you cannot make use of a standard class library. Instead, we will have to make use of the Portable Class Library as shown below –

pcllibrary

Write the same code in our portable class library as shown here –

public static class StringExtensions
{
    public static bool FindWord(this string s, string message, string wordToFind)
    {
        return Regex.IsMatch(message, wordToFind);
    }
}

Compile the library and try adding the same into a.NET application as well as into a Silverlight and Windows Store App. Now the library reference will be added to the project as shown here –

pcllibreference

Let’s make use of this library in our Windows Store app. The design of the Windows Store App is as following –

< stackpanel background=""Black"" margin=""100"">
< textbox text=""Wel" come="" to="" fontsize=""20"" name=""txtString"">
< button content=""Search" name=""btnSearch"" margin=""50"" click=""btnSearch_Click"">
< textblock name=""txtResult"" fontsize=""20"">

In the code file, we will first import the library reference and then write some code on the button click event –

private void btnSearch_Click(object sender, RoutedEventArgs e)
{
    string searchText = txtString.Text;
    bool result = searchText.FindWord(searchText, "India");
    if (result==true)
    {
        txtResult.Text = "Word Match Found";
    }
    else
    {
        txtResult.Text = "Didn't find the word match";
    }
}

Run the program and you will see the following output -

winstoreappoutput

Extend ASP.NET MVC classes using Extension Methods

We will extend an ASP.NET MVC framework class by using Extension methods. We will extend the HTML Helper by adding an Extension method with the name “ReplaceWord”. The primary job of this method will be to find out the words which we would like to delete from the content.

We will create an ASP.NET MVC application and then add a class in our ASP.NET MVC application with the name HTMLHelperExtensions and write the method “ReplaceWord” –

public static class HTMLHelperExtensions
{
    public static MvcHtmlString ReplaceWord(this HtmlHelper htm, string msg, string findWord)
    {
        bool result=Regex.IsMatch(msg, findWord);
        return new MvcHtmlString(msg.Replace(findWord, "" + findWord + ""));
    }
}

Now we will use this Extension method in our Home Controller. Add an Action method in our Home Controller as shown here –

public ActionResult TestExtMethod()
{
    ViewBag.Message = "This is not possible in a real word scenarios!!";
    return View();
}

Once you add the action method, we will now create a view for the TestExtMethod. Once the view is ready, we will use our Extension method in the view. To use the Extension method in a view, we will first import the namespace in our view and then code our view in the following manner –

mvcviewcode

Run your application and see the output. It should look the following –

mvcextoutput

Extend ASP.NET Web API using Extension Methods

Similarly you can use Extension methods to extend the ASP.NET Web API too. Start by creating a new Web API project in Visual Studio 2013 as shown here –

Add a class with the name WebAPIExtensions and write the following code –

public static class WebAPIExtensions
{
public static void ClientIPHeader(this HttpResponseMessage response, HttpRequestMessage request)
{
    var httpContextWrapper = request.Properties["MS_HttpContext"] as HttpContextWrapper;
    if (httpContextWrapper != null)
    {
        var ipAddress = httpContextWrapper.Request.UserHostAddress;
        response.Headers.Add("clientIP", ipAddress);
    }
}
}

This Extension method adds a client IP address with a response message. Let’s use this Extension method in our Web API. Add a class with the name Customer into our Models folder and write the following code in it

public class Customer
{
    [Key]
    public int CustomerID { get; set; }
    public string Name { get; set; }
}

Install Entity Framework using the NuGet Package in the project. To create a database with the table we will have to create a data context class as shown here –

public class TestEntities:DbContext
{
    public TestEntities():base("Data Source=localhost;Initial Catalog=Test;Integrated Security=true;")
    {

    }
    public DbSet Customers { get; set; }
}

Add a new Web API with the name CustomersController as shown here –

webapi2

Write the following code in our Customers Controller –

public class CustomersController : ApiController
{
    TestEntities dataContext = new TestEntities();
    public IEnumerable Get()
    {
        var query = from cust in dataContext.Customers
                    select cust;
        return query.ToList();
    }
    public HttpResponseMessage Post([FromBody]Customer c)
    {
        dataContext.Customers.Add(c);
        dataContext.SaveChanges();
        var res = new HttpResponseMessage(HttpStatusCode.Created);
        res.ClientIPHeader(Request);
        return res;
    }
}

I am using Fiddler to inspect the response header to check the client IP address. The output is as shown here –

responseheaders

Likewise you can extend Framework classes, Custom classes and even Third party classes without inheriting them. Extension methods are a powerful means by which you can extend classes, interfaces, collection classes, enums etc.

Extension Method Advantages –

  • Extension methods extend the existing type system whether it is a framework class, your own custom class or third party API. You can also use Extension methods to extend sealed classes [Not Inheritable].
  • The advantage of using Extension method is that it appears in Visual Studio Intellisense when you access an object of type which you are extending.
  • Extension methods can be used to extend Classes, Interfaces, Collections, Structures, Enum etc.

Extension Method Limitations –

  • You cannot write Extension Methods with the same signature. For example you are extending a framework class Object and your team member is also extending the Object class using Extension method. Accidently if the signature of both the method is the same, then it throws you an ambiguous exception when you will call the method.
  • Avoid using Reflection while working with Extension methods. Sometimes you may want to call the non-public members of the class which you are extending using Extension methods, however that’s not possible because Extension methods can only access public members of the class. In such a situation, you may use Reflection. This will work but in case the class members get changed, then there will be an issue while calling the Extension methods. For example you are calling a method Foo() from the class in an extension method using reflection and someone changed the method from Foo to Foo1, it will throw you an exception.
  • What if you declare an Extension method which is already declared by the class? In this situation, the compiler will give priority to the method which is declared in the class and not to an Extension method.
  • Extension methods are scoped at namespace level. For example, if you are extending an object class using Extension method in ABC namespace, you cannot use this extension method in XYZ namespace. For this, either add an extension method at System namespace or import the namespace. In our case it is ABC.

Extension methods are a special kind of static method, but are called as if they were instance methods on the extended classes/structure. Use them sparingly and only where required!

Was this article worth reading? Share it with fellow developers too. Thanks!
Share on LinkedIn
Share on Google+
Further Reading - Articles You May Like!
Author
Pravinkumar, works as a freelance trainer and consultant on Microsoft Technologies. He is having over 10 years of experience in IT and is also a Microsoft Certified Trainer(MCT). He has conducted various corporate trainings on all versions of .NET Technologies including .NET, SharePoint Server, Microsoft SQL Server, Silverlight, ASP.NET, Microsoft PerformancePoint Server 2007 (Monitoring). He is passionate about learning new technologies from Microsoft. You can contact Pravinkumar at dabade[dot]pravinkumar [attherate] gmail[dot]com


Page copy protected against web site content infringement 	by Copyscape




Feedback - Leave us some adulation, criticism and everything in between!
Comment posted by negablog on Wednesday, November 5, 2014 7:07 AM
http://www.negablog.com/2014/11/create-custom-extension-method-in-c.html