Przykłady wykorzystania mechanizmu metod rozszerzających w C# 3.0

Metody rozszerzające są nową cechą języka C# 3.0. Pozwalają one rozszerzać istniejące typy (klasy i struktury) o nowe metody. Nie ma, niestety, możliwości dodawania nowych własności, ale to co jest i tak pozwala na ciekawe eksperymenty z własnymi DSLami (językami specyficznymi dla domeny).

Aby zdefiniować rozszerzenie metod, należy:

  • zdefiniować klasę statyczną (o dowolnej nazwie),
  • wewnątrz tej klasy zdefiniować statyczną metodę, która jako pierwszy parametr przyjmuje parmetr o sygnaturze: this TypRozszerzany instancja.

Potem metodę taką można wykonać na każdej instancji danej klasy identycznie jak metody wbudowane.

W niniejszym artykule podane zostaną dwa krótkie i proste przykłady jak korzystając z metod rozszerzających zaimplementować cukierki składniowe znane z języka Ruby oraz platformy Ruby on Rails.

1. Metoda Do.

Sposób 1 - przez obiekt proxy

Rozszerzenie

public delegate void VoidFunc<T>(T arg);
 
public class TimesProxy
{
    public TimesProxy(int initNumber)
    {
        number = initNumber;
    }
 
    public void Do(VoidFunc<int> block)
    {
        for(int i = 0 ; i < number ; ++i)
        {
            block(i);
        }
    }
 
    private int number;
}
 
public static class IntegerExtensions1
{
    public static TimesProxy Times(this int number)
    {
        return new TimesProxy(number);
    }
}

Wykorzystanie

12.Times().Do( (i) => Console.WriteLine(i)) ;

Sposób 2 - bezpośrednio przez metodę

Rozszerzenie

public delegate void VoidFunc<T>(T arg);
 
public static class IntegerExtensions2
{
    public static void TimesDo(this int number, VoidFunc<int> block)
    {
        for (int i = 0; i < number; ++i)
        {
            block(i);
        }
    }
}

Wykorzystanie

12.TimesDo( (i) => Console.WriteLine(i) );

2. Rozszerzenia dla daty i czasu

Rozszerzenie

public static class DateTimeIntegerExtensions
{
    public static TimeSpan Days(this int numOfDays) { return TimeSpan.FromDays(numOfDays); }
    public static TimeSpan Hours(this int numOfHours) { return TimeSpan.FromHours(numOfHours); }
    public static TimeSpan Minutes(this int numOfMinutes) { return TimeSpan.FromMinutes(numOfMinutes); }
}
 
public static class DateTimeExtensions
{
    public static DateTime Ago(this TimeSpan timeSpan) { return DateTime.Now - timeSpan; }
}

Wykorzystanie

DateTime someTimeAgo = DateTime.Now - (10.Days() + 4.Hours() + 35.Minutes());

if (someTimeAgo < 12.Days().Ago())
{
    Console.WriteLine("Earlier than 12 days ago");
}
else
{
    Console.WriteLine("Later than 12 days ago");
}
O ile nie zaznaczono inaczej, treść tej strony objęta jest licencją Creative Commons Attribution-Share Alike 2.5 License.