Cloud Power

Все про .NET, Windows Azure и SQL Server

C# Tips 4: Расширение Enums с помощью Extension Methods

В этом посте пойдет речь о использовании Extension Methods для реализации доп. методов в перечислениях(enums)

Давайте построим перечисление, которое будет содержать все стороны света(Север, Юг, Запад, Восток). Ну все просто)

Выглядит где-то так:

 public enum CompassPoints
    {
        North,
        East,
        South,
        West
    }

Нам необходимо сделать так, чтобы у нашего перечисления появились некие методы, которые смогут возвращать нам следующюю по часовой или против часовой стрелки сторону света(Для более удобного метода установки направления). Для этого нам необходимо будет воспользоватся методами расширения.

Реализация примерно следующая:

public static class CompassPointsExtension
    {
        public static CompassPoints Next(this CompassPoints value)
        {
            var valueCompassPoint = (int)value + 1;
            if (valueCompassPoint == 4)
            {
                valueCompassPoint = 0;
            }
            return (CompassPoints)valueCompassPoint;
        }

        public static CompassPoints Prev(this CompassPoints value)
        {
            var valueCompassPoint = (int)value - 1;
            if (valueCompassPoint == -1)
            {
                valueCompassPoint = 3;
            }
            return (CompassPoints)valueCompassPoint;
        }
    }

Здесь можно увидеть несколько основных моментов, которые всегда используются в методах расширения:

1)Класс, в котором находятся методы расширения, должен быть статическим;

2)Методы должны быть тоже статические(Хотя по другому быть и не может. В статическом классе могут быть только статические члены)

3)И необходимо вставить ключевое слово this перед типом, который вы хотите расширить

Результат:

static void Main(string[] args)
        {
            CompassPoints point = CompassPoints.North;
            Console.WriteLine(point);
            point = point.Next();
            Console.WriteLine(point);
            point = point.Prev();
            Console.WriteLine(point);
        }

И вывод:

Screen Shot 2012-04-08 at 2.12.36 AM

Это очень классный способ выполнить расширение типов, которые дополнены или расширены быть не могут.

Спасибо за внимание!

Реклама

C# Tips 3: Rethrow exception

Сегодня мы поговорим про метод перевыброса объектов ошибок без изменения оригинального места их появления.

Ну в принципе перевыбросить Exception можно двумя способами.

1)

class Program
    {
        static void Main(string[] args)
        {
            try
            {
                Method();
            }
            catch (DivideByZeroException ex)
            {
                //TODO:Logging code here!
                throw ex;
            }
        }

        public static void Method()
        {
            throw new DivideByZeroException();
        }
    }

2)

class Program
    {
        static void Main(string[] args)
        {
            try
            {
                Method();
            }
            catch (DivideByZeroException ex)
            {
                //TODO:Logging code here!
                throw;
            }
        }

        public static void Method()
        {
            throw new DivideByZeroException();
        }
    }
Первый вариант ведет себя правильно, но все же в нем есть один существенный недостаток — в нем замещается текущее положение указателя в стеке, где возникает Exception(Я думаю вам не особо этого хочется. Проблем не огребете во время отладки).
Сам стек для первого варианта:
 
Здесь мы можем увидеть что оригинальный источник потерян(Напомню это метод Method())!
Стек для второго варианта:
А вот здесь мы видим что оригинальный источник не потерялся.
Ох намаялся я пару раз с этой штукой)
Спасибо за внимание!

C# Tips 2: Форматирование типа

В этом посте мы с вами рассмотрим форматирование типа с помощью метода ToString() и реализации интерфейса IFormattable

Начнем с метода ToString(). Представьте есть структура следующего вида:

public struct Point

{

public double X { get; set; }

public double Y { get; set; }

public Point(double x, double y) : this()

{

this.X = x;

this.Y = y;

}

}

Если создать экземпляр структуры и для вывода на экран воспользоваться методом ToString(), то получим следующее:

static void Main(string[] args)
{
Point p1 = new Point(10,10);
Console.WriteLine(p1.ToString());
}
Но это отнюдь не то что мы хотели увидеть. А мы хотим видеть выведение структуры в виде Point: (X;Y)
Вот для этого мы выполним перегрузку метода ToString();
public override string ToString()
{
return String.Format("Point: ({0};{1})", this.X, this.Y);
}

И вот после этого результат вывода будет точь в точь такой как мы хотим:


Вообщем метод ToString() делает свою работу очень хорошо, но есть один нюанс этот метод не очень гибок! Мы не можем управлять форматированием вывода во время вызова метода ToString(). Для того что бы появилась возможность это делать(в нашем случае выводить только, например координату Х или Y),  мы будем реализовывать интерфейс IFormattable. Это превратит метод ToString() в максимально гибкий вариант использования.

public struct Point : IFormattable
{
#region Previous code

public double X { get; set; }
public double Y { get; set; }

public Point(double x, double y)
: this()
{
this.X = x;
this.Y = y;
}

public override string ToString()
{
return String.Format(“Point: ({0};{1})”, this.X, this.Y);
}

#endregion

public string ToString(string format, IFormatProvider formatProvider)
{
if (String.IsNullOrEmpty(format)) format = “G”;

if (format == “G”)
{
return String.Format(“Point: ({0};{1})”, this.X, this.Y);
}
var sb = new StringBuilder();
var index = 0;
while (index < format.Length)
{
switch (format[index])
{
case ‘X’:
sb.Append(String.Format(“X coordinate: {0}, “,this.X));
break;
case ‘Y’:
sb.Append(String.Format(“Y coordinate: {0}”,this.Y));
break;
}
index++;
}
return sb.ToString();
}
}

* This source code was highlighted with Source Code Highlighter.

Вот такая реализация. При вызове метода ToString() с параметром formatter(Первый параметр)

p1.ToString(«XY»,null) будет выведено «X coordinate: 10, Y coordinate: 10»

p1.ToString(«X»,null) будет выведено «X coordinate: 10,»

p1.ToString(«Y»,null) будет выведено «Y coordinate: 10»

p1.ToString(«G»,null) будет выведено «Point: (10;10)»

 Про второй параметр мы поговорим как нибуть в другой раз(Да, кстати он называется IFormatProvider)!