C# 3.0: I like Extension Methods


After the declaration of C# 3.0 I went ahead and installed the PDC bits. After reading through the language spec. I was very very very unhappy. I mean we were just getting excited over C#2.0 supporting generics, anonymous mehtods, Nullable types and then suddenly someone ruins all the fun by showing us C#3.0. C#2.0 already appears stale. Some great blogs on this are from Cyrus and Matt Warren


The good part is that since I work in Microsoft, soon (after VS 2005 release I guess) we’d move to C#3.0 to dogfood it. So that means I’ll not be required to wait for the super enhancements in C# for long!!!!


I thought I’d try out the features of C#3.0 and write some stuff on it. Here goes the second one (the first is already there)


Extension Methods


With extension methods you can attach additional functionalities to an existing type even if you do not have access to it. For example I can write an  extension method Print() which prints each element of any collection on a different line and then invoke it on any collection such as

List<string> first = new List<string>();

first.AddRange (new string[] {“Hello”, “how”});

first.Print();


Importantly note is that even though Print() is not a member of List<> but is still called as if its a method. There are a couple of restrictions in defining the extension method Print. All of which are marked in bold in the example below

public static class Extensions

{

public static void Print<T>(this ICollection<T> col)

{

foreach(T t in col)

Console.WriteLine(t);

}

}

static void Main(string[] args)

{

List<string> first = new List<string>();

first.AddRange (new string[] {“Hello”, “how”});

first.Print();

}


The method has to be a static method in a static class. The first parameter to the method has to be qualified using this and this first parameter indicates the types on which this extension method can be applied. Its important to note that this is just syntactic sugar and both the following calls are equivalent and legal.

first.Print();

Extensions.Print(first);


So whats the benefit? I think this makes code more elegant and this can be used very much like C++ STL algorithms. Lets say I write a merge algorithm that merges two collections and then I’d be able to call this merge algorithm on any collection in a very elegant way. Following is the implementation of a merge algorithm


using System;
using
System.Collections.Generic;
// Will compile only with C#3.0 complilers
namespace
ExtensionMethodDemo
{
    public static class
Extensions
    {
        public static void Merge<T>(this ICollection
<T> first, ICollection<T> second)
        {
            foreach(T t in
second)
                first.Add(t);
        }
   
}


    class Program
    {
        static void Main(string
[] args)
       
            List<string> first = new List<string
>();
            first.AddRange (
new string[] {“Hello”, “how”
});

            List<string> second = new List<string
> ();
            second.AddRange (
new string[] {“are”, “you”, “doing”
});

            first.Merge(second);
        }
    }
}


Moreover the class libarary already ships with some standard extension methods (like standard algorithms of STL) and you can directly use them. Consider the following

int[] a = new int[] {1, 2, 2, 4, 3};

Console.WriteLine(a.Distinct().Count());


Here two of the methods Distinct and Count are used and the combined result is that we get the number of distinct elements in the array and that is 4. This is really really cool.


As a real life sample I wrote a pretty print extension method that prints the directory listing is a pretty fashion.


using System;
using System.Collections.Generic;
using System.Text;
using System.Query;
using System.IO;


namespace ExtDemo
{
   
    public static class Extensions
    {
        public
static void PrettyPrint(this
IEnumerable<FileInfo> fInfo)
        {
            ConsoleColor defColor = Console.ForegroundColor;
            string format = “{0, -17} {1,10} {2}”;
            Console.ForegroundColor = ConsoleColor.Green;
            Console.WriteLine(format,
“Date”, “Size (kb)”, “File name”);
            Console.ForegroundColor = defColor;
            foreach(FileInfo file in fInfo)
            Console.WriteLine(format, file.CreationTime.ToString(
“dd/MM/yyyy hh:mm”), (float)file.Length / 1024, file.Name);
        }
    }
    class Program
    {
        static void Main(string[] args)
       
            DirectoryInfo
dirInfo = new DirectoryInfo(@”c:\”);
            dirInfo.GetFiles().PrettyPrint();
        }
    }
}


The C# 3.0 spec clearly calls out that since this is not a very discoverable feature and is somewhat misleading (very much like operator overloading) and so should be used sparingly. I think that this’ll be more and more used by class libraries to implement STL like algorithms that can be run on containers.

Comments (24)

  1. Anonymous says:

    This is the my third post on the series of post I am making on C#3.0 after it got declared on PDC. See…

  2. Anonymous says:

    This is the my third post on the series of post I am making on C#3.0 after it got declared on PDC. See…

  3. Anonymous says:

    This is the my fourth post in the series of posts I am making on C#3.0. See the previous posts here,…

  4. Anonymous says:

    This is the my fifth post in the series of posts I am making on the new features in C#3.0. See the previous…

  5. Anonymous says:

    This is the my fifth post in the series of posts I am making on the new features in C#3.0. See the previous…

  6. Anonymous says:

    This is the my fifth post in the series of posts I am making on the new features in C#3.0. See the previous…

  7. Anonymous says:

    This is the my fifth post in the series of posts I am making on the new features in C#3.0. See the previous…

  8. Anonymous says:

    As I had previously said I love extension methods&amp;nbsp;and have started using them at multiple places…

  9. Anonymous says:

    i want to print a windoe form  on printer

    whats this method?

    thanks

  10. Anonymous says:

    i want to print a window form  on printer

    whats this method?

    thanks

  11. Anonymous says:

    &amp;nbsp;Jim Wooley, leader of the Atlanta Visual Basic Study Group, presented to the Atlanta C# User Group…

  12. Anonymous says:

    &amp;nbsp;Jim Wooley, leader of the Atlanta Visual Basic Study Group, presented to the Atlanta C# User Group…

  13. Anonymous says:

    I love extension methods.

    for "int[] a = new int[] {1, 2, 2, 4, 3};", you can write this with C#3.0 : "int[] a = {1, 2, 2, 4, 3};" isn’t it great?

  14. Anonymous says:

    Really its an awesome thing. Its gonna be widely used. Many of us would face this problem of adding a new method to an existing class, so it will definitely be helpfull.

  15. Ian Suttle says:

    Thanks for this article.  I’ve included a bit more info on extension methods on my blog as well: http://www.iansuttle.com/blog/post/Extension-Methods-in-C-30.aspx

  16. Chui says:

    Thanks. What happens when identical signatures clash?

  17. substr() vs String.Substring()

  18. Today I was spreading the goodness of Ruby and why I love it so much (and you can expect multiple posts

  19. Today I was spreading the goodness of Ruby and why I love it so much (and you can expect multiple posts

  20. Page Brooks says:

    Cool C# 3.0 Extension Method Idea

  21. After the declaration of C# 3.0 I went ahead and installed the PDC bits . After reading through the language spec . I was very very very unhappy. I mean we were just getting excited over C#2.0 supporting generics, anonymous mehtods, Nullable types an