Feel Good.

20 апреля 2010

Extension Methods как «Синтаксический сахар»

Решил начать собирать на этой страничке интересные и полезные решения на базе Extension Methods, которые облегчают процесс написания кода, или другими словами «Синтаксический сахар».

Приведу некоторые из них:
  1. На днях, изучал исходники проекта KIGG и встретил там удобный вариант форматирования строки, взамен String.Format:

    public static string FormatWith(this String target, params object[] args)

    {

        return string.Format(target, args);

    }


    Пример:

    string line = "Hello, {0}".FormatWith("Ilya");



  2. Преобразование строки в тип перечисления (Enum):

    public static TEnum CastToEnum<TEnum>(this string input, bool ignoreCase)

    {

        return (TEnum)Enum.Parse(typeof(TEnum), input, ignoreCase);


    Пример:

    DayOfWeek day = "Sunday".CastToEnum<DayOfWeek>(true);


    Можно добавить значение по-умолчанию в сигнатуру метода.

  3. Удобное приведение к типу, взамен as и is:

    public static T As<T>(this object obj)

        where T : class

    {

        return obj as T;

    }

     

    public static T Like<T>(this object obj)        

    {

        return (T)obj;

    }

     

    public static bool Is<T>(this object obj)

    {

        return obj is T;

    }


    Пример:

    object o1 = true;

    bool isbool = o1.Is<Boolean>();

     

    object o2 = "abc";

    string str = o2.As<String>();

     

    object o3 = 123;

    Int32 num = o3.Like<Int32>();



  4. В одном из Mock фреймворков (Rocks) встретил интересную запись цикла for:

    public static void Times(this int count, Action<int> action)

    {

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

            action(i);

    }


    Пример:

    5.Times(i => Console.WriteLine(i));



  5. Проверка, что строка непустая:

    public static bool IsNullOrEmpty(this string self, bool trim)

    {

        if (self == null)

            return true;

     

        if (trim)

            self = self.Trim();

     

        return string.IsNullOrEmpty(self);

    }


    Пример:

    bool empty = "  ".IsNullOrEmpty(true);


    Кстати, для null тоже работает, хотя и вводит в заблуждение:

    string nul = null;

    // Вернет true

    bool isnul = nul.IsNullOrEmpty(true);


  6. .NET Extensions - Extension Methods Library
  7. EventHandler extention
  8. Продолжение следует...Буду благодарен, если Вы предложите в комментариях свои решения.

10 комментариев:

  1. из того же KIGG еще полезная вещь
    public static string NullSafe(this string target)
    {
    return (target ?? string.Empty).Trim();
    }

    ОтветитьУдалить
  2. Я часто еще встречаю MD5 расширение для типа String.

    ОтветитьУдалить
  3. public static class StreamExtensions
    {
    public static byte[] ToArray(this Stream source)
    {
    if (source is MemoryStream)
    {
    return ((MemoryStream)source).ToArray();
    }

    if (source.CanSeek)
    {
    var oldPosition = source.Position;
    source.Position = 0;
    var result = new byte[source.Length];
    source.Read(result, 0, result.Length);
    source.Position = oldPosition;
    return result;
    }

    var buffer = new byte[BufferSize];
    int read;
    var resultStream = new MemoryStream();
    while ((read = source.Read(buffer, 0, BufferSize)) > 0)
    {
    resultStream.Write(buffer, 0, read);
    }

    return resultStream.ToArray();
    }

    public static Stream ToStream(this byte[] source)
    {
    return new MemoryStream(source);
    }

    private const int BufferSize = 128 * 1024;

    public static void WriteTo(this Stream source, Stream target)
    {
    var buffer = new byte[BufferSize];
    var oldPosition = -1;
    if (source.CanSeek)
    {
    oldPosition = source.Position;
    source.Position = 0;
    }

    int read;
    while((read = source.Read(buffer, 0, BufferSize)) > 0)
    {
    target.Write(buffer, 0, read);
    }

    if (oldPosition != -1)
    {
    source.Position = oldPosition;
    }
    }
    }

    ОтветитьУдалить
  4. Еще, как вариант форматирования денежных сумм, можно так:

    public static string ToCurrency(this decimal money)
    {
    return string.Format("{0:C}", money);
    }

    ОтветитьУдалить
  5. ForEach, о целесообразности которого идут споры:
    public static void ForEach(this IEnumerable source, Action action)
    {
    foreach (var item in source)
    {
    action(item);
    }
    }

    public static void ForEach(this IEnumerable source, Action action, TArg arg)
    {
    foreach (var item in source)
    {
    action(item, arg);
    }
    }

    public static void ForEach(this IEnumerable source, Action action, TArg1 arg1, TArg2 arg2)
    {
    foreach (var item in source)
    {
    action(item, arg1, arg2);
    }
    }

    Маленькие вкусности для коллекций:

    public static void Truncate(this List source, int count)
    {
    source.RemoveRange(count, source.Count - count);
    }

    public static void AddRange(this ICollection source, IEnumerable items)
    {
    items.ForEach(source.Add);
    }

    Формирование последовательностей на-лету:

    public static IEnumerable Enumerate(this T value)
    {
    yield return value;
    }

    public static IEnumerable Enumerate(this T value1, T value2)
    {
    yield return value1;
    yield return value2;
    }

    public static IEnumerable Enumerate(this T value1, T value2, T value3)
    {
    yield return value1;
    yield return value2;
    yield return value3;
    }

    public static IEnumerable Enumerate(this T value1, T value2, T value3, T value4)
    {
    yield return value1;
    yield return value2;
    yield return value3;
    yield return value4;
    }

    public static IEnumerable Append(this IEnumerable source, T value)
    {
    return source.Concat(value.Enumerate());
    }

    public static IEnumerable Append(this IEnumerable source, T value1, T value2)
    {
    return source.Concat(value1.Enumerate(value2));
    }

    public static IEnumerable Append(this IEnumerable source, T value1, T value2, T value3)
    {
    return source.Concat(value1.Enumerate(value2, value3));
    }

    Имя "Enumerate" возможно не очень здесь подходит, просто хотелось имя покороче

    ОтветитьУдалить
  6. Парсер зохавал все угловые скобки. Надеюсь и так понятно будет

    ОтветитьУдалить
  7. Не совсем понимаю, почему o1.Is() удобнее, чем o1 is boolean? По-моему, совершенно лишнее.

    ОтветитьУдалить
  8. @SKINDER

    На то он и "синтаксический сахар", что без него можно обойтись).

    Но например:
    Вместо (o1 is boolean).ToString()
    можно так o1.Is<Boolean>().ToString()
    Получается нечто fluent interface.

    ОтветитьУдалить
  9. вот,часто юзаю
    /// Выполняет функцию case1 если src не null, иначе выполняет функцию case2
    public static R Map(this T src, Func case1, Func case2)
    {
    return src != null
    ? case1(src)
    : case2(src);
    }

    /// Выполняет функцию если src не null, иначе возвращает def
    public static R Map(this T src, Func selector, R def)
    {
    return src != null
    ? selector(src)
    : def;
    }

    /// Выполняет функцию если src не null
    public static R Map(this T src, Func selector)
    {
    return src != null
    ? selector(src)
    : default(R);
    }

    el.Attribute("displayName").Map(v => result += string.Format("\r\n\t {0}", v.Value));

    ОтветитьУдалить
  10. @anemon
    Спасибо, интересное решение. Можно даже назвать метод CaseByNull или что-то в этом роде.

    ОтветитьУдалить