วันอาทิตย์ที่ 16 ธันวาคม พ.ศ. 2550

How to use Extension Methods to extend C# language

Start my first blog with coding!

Usually, when we want to extend a type, we need to create a new derived type. But creating a new derived type, sometimes it is not suitable. Sometimes the extensions are so small, sometimes types are sealed and unable to be extended. Another solution is you can create new static methods. But those methods are not become parts of the type. New Visual Studio 2008 has a new feature enables you to add new methods without having to derive a type and able to create new methods that will become a part of the type. This new feature called "Extension Methods".

Interesting point is, we can use "Extension Methods" to enhance built-in types like int or IEnumerable. And that could change style of coding which totally different from C# 2.0. Do you know Ruby? Ruby is a programming language that is short and easy. Let's make C# to be as easy as Ruby.

Start with foreach. When you enumerate items in a list you use:

foreach (Object item in list)

But not in Ruby, in Ruby we just write:

list.each{|item| ...}

How easy! To make code like Ruby, put this source on your extension class.

public static void ForEach<T>(this IEnumerable<T> source, Action<T> action) {
    foreach (T item in source)
        action(item);
}

public static void ForEach<T>(this IEnumerable<T> source, Action<T, int> action) {
    int i = 0;

    foreach (T item in source)
        action(item, i++);
}


After extension, you can write:

list.ForEach(item => ...);
list.ForEach((item,index)=> ...);

Here is the example:

string[] persons = new string[] {"Jack", "Lisa", "Ryan"};
persons.ForEach(person => Console.WriteLine("Hello {0}!", person));
//Hello Jack!
//Hello Lisa!
//Hello Ryan!


persons.ForEach((person, index) => Console.WriteLine("{0}. {1}", index + 1, person));
//1. Jack
//2. Lisa
//3. Ryan


Is that ok with you? If you like Ruby style go to next method. When we run number 0 to 2 (run 3 loop) we usaully write:

for (int i = 0; i <= 2; i++)

Ruby is much easily:

0..2

or

3.times{|x| ..}

Jealous? Put this source on your extension class:

public static IEnumerable<int> To(this int from, int to) {
    for (int x = from; x <= to; x++)
        yield return x;
}
public static IEnumerable<int> DownTo(this int from, int to) {
    for (int x = from; x >= to; x--)
        yield return x;
}
public static IEnumerable<int> StepTo(this int from, int to, int step) {
    if (step > 0) {
        for (int x = from; x <= to; x += step)
            yield return x;
    } else if (step < 0) {
        for (int x = from; x >= to; x += step)
            yield return x;
    } else {
        throw new ArgumentException("Step cannot be zero.", "step");
    }
}
public static void Times(this int num, Action<int> action) {
    for (int x = 0; x < num; x++)
        action(x);
}


Now you can write:

string[] persons = new string[] { "Jack", "Lisa", "Ryan" };
0.To(2).ForEach(i => Console.WriteLine(persons[i]));
//Jack
//Lisa
//Ryan

2.DownTo(0).ForEach(i => Console.WriteLine(persons[i]));
//Ryan
//Lisa
//Jack

0.StepTo(2, 2).ForEach(i => Console.WriteLine(persons[i]));
//Ryan
//Jack
//(run 0 to 2 with step 2)

3.Times(i => Console.WriteLine(persons[i]));
//Jack
//Lisa
//Ryan


Try practical use, with question from projecteuler.net.
Add all the natural numbers below 1000 that are multiples of 3 or 5.

Console.WriteLine(1.To(999).Where(x => (x % 3 == 0) || (x % 5 == 0)).Sum());
//233168


Now we can completed question above with only one line of code. If you use C# 2.0, you will never write code like this. There are more several methods that you can extend C# from Ruby (or any other languages). Make your code shorter, your life will be easier.

ไม่มีความคิดเห็น: