Showing posts with label Extension methods. Show all posts
Showing posts with label Extension methods. Show all posts

Sunday, January 29, 2012

C# 3.0 for Beginners - Extension Methods - Part 2


Custom Extension Methods

C# 3.0 enables you with the ability to extend the functionality of existing types. This means that you can write your own extension methods that would give the programmer the feeling that those are just methods provided by the existing type.

For example, System.Int32 doesn't provide you an IsEven() method which would tell you if the integer is holding an even value. It would obviously be great if you could write a method which does this, just in case you use this functionality heavily in your code. You would then write a method like this
public bool IsEven(Int32 i)
{
    if(i%2 == 0)
    {
        return true;
    }
    else
    {
        return false;
    }
}

Well, that's perfectly fine. But, I wish we could make it more easier. And I bet we can for sure, that's what extension methods are here for. No, we cannot go and implement the IsEven() method for the Int32 type, but C# 3.0 allows you to extend type functionality in a different way.

Check out the following code. I'm extending the Int32 type to expose the Int32.IsEven() extension method.
public static class MyIntegerExtensionMethod
{
    public static bool IsEven(this Int32 i)
    {
        if (i % 2 == 0)
        {
            return true;
        }
        else
        {
            return false;
        }
    }
}

public class Program
{
    static void Main(string[] args)
    {
        Int32 n = 9;
        Console.WriteLine(n.IsEven());
    }
}

Let's look at the most important part, the method signature.
public static bool IsEven(this Int32 i)

A template for the above would be

<access_modifier> static <return_type> Method_Name(this <extended_type> <instance_of_type>, <args_list>)

While <access_modifer> and <return_type> are intuitive, special attention is needed at the parameters of the method. The first parameter resembles the type which is to be extended, preceded with the 'this' keyword. The arguments that follow are the actual arguments/parameters to the method.

Another thing to remember is that extension methods should be defined as static members in a static class. The only difference between a normal method and an extension method is that the first parameter of an extension is always prefixed with the 'this' keyword. The rest are normal parameters. Also, when using the extension method you should remember to keep the extension method within the scope of its usage or you could even include it using the 'using' directive.

Usage Restrictions
  • Extension methods can access only the public members of the type being extended.
  • If you define an extension method whose signature matches with the method already existing in the extended type, priority is given to the existing method and the new extension method is ignored.
Have fun with this great feature!

C# 3.0 for Beginners - Extension Methods - Part 1

All C# code is eventually executed by the .NET CLR. This requires the C# compiler to transform the LINQ query expressions to a format that is understandable by .NET. LINQ query expressions are transformed into method calls, which are called extension methods. These methods are slightly different from normal methods. Lets discuss them in more detail:

Consider the example that we saw in my previous posts.
    public static void GetIExplorer()
    {
        //  1. Data Source
        Process[] processes = Process.GetProcesses();

        //  2. Query Creation
        IEnumerable<int> query =
              from p in processes
              where p.ProcessName.ToLower().Equals("iexplore")
              select p.Id;

        //  3. Query execution
        foreach (int pid in query)
        {
            Console.WriteLine("Process Id : "+pid);
        }
    }

The query creation in part two transforms in a series of method calls on the data source 'processes' as follows.
    IEnumerable<int> query =
            processes.Where(p => p.ProcessName.ToLower().Equals("iexplore"))
                     .Select(p => p.Id);

The Select clause, however, it not essential. It may be ignored and you might retrieve a list of processes and not their process Ids. The Select clause here specifies the entity to be selected in detail, in the above example, it was the process id belonging to the selected process.

Now, you might wonder that since the Where() method was called on the 'processes' Array, the Array object might have implemented the Where() method. But, that's not quite the case here. The method Where() is called an extension method and is used for extending a type's functionality.

We have also made use of lambda expressions here. We will discuss their significance later in detail, but, for now, you can look at it as if it were a provision to select entities based in certain specified conditions. In the above code the variable 'p' indicates each element in the 'processes' array which is subjected to an expression evaluation (p.ProcessName.ToLower().Equals("iexplore")), and only if the result of the condition evaluation is true, will the item be selected as the result of the query. These are filtering expressions.

In my next post I will describe how to define and use your own extension methods.