Несколько дней назад появилась задача глубокого (deep cloning) клонирования бизнес-объектов NHibernate. Сначала хотел реализовать с помощью Xml-сериализации. Однако известно, что интерфейсы не сериализуются:
1
public virtual IList Clubs { get; set; }
Писать метод клонирования в базовом классе с применением Reflection я не стал — не всегда гибкое решение. Благо наткнулся на AutoMapper. Данный OOM представляет собой одну единственную dll. Для использования мэппера добавляем ссылку на AutoMapper и подключаем пространство:
1
using AutoMapper;
А затем в нужном методе, например, пишем:
1
2
3
4
5
6
7
var transact = (Transaction)lvTransactions.SelectedItem;

Mapper.CreateMap<Transaction, Transaction>();
var newtransact = new Transaction();
Mapper.Map(transact, newtransact);

newtransact.Quantity *= -1;

Задача — добавить в список транзакций транзакцию с ценой, обратной выбранной. Так у меня в списке lvTransactions выбирается транзакция. Далее указываем тип объектов, которые будут мэппится (для клонирования один тип Transaction). Создается новый объект newtransact, и происходит «клонирование» посредством AutoMapper. В итоге поставленная задача решена двумя строками кода.

В настоящее время разрабатываю проект на базе .NET Framework 3.5 (C#/WPF/NHibernate и пр.). В ходе разработки появилась необходимость распарсить строку вида «ORDER20100322194007», где «20100322194007» — дата и время: 2010-03-22 19:40:07.000. Причем строка всегда начинается со слова «ORDER» («Заказ»).

Решение:

1
2
3
4
5
6
7
8
9
10
11
12
string pattern = "'ORDER'yyyyMMddHHmmss";
DateTime dt;
if (DateTime.TryParseExact(text, pattern, CultureInfo.InvariantCulture,
                           DateTimeStyles.None,
                           out dt))
{
    // dt - результат парсинга.
}
else
{
    // Строка не подходит под паттерн, заданный изначально.
}

Иногда у разработчика возникает необходимость вызывать какой-либо метод, определенный в форме из другой формы. Начинающих такая задача ставит в ступор, поэтому привожу 2 наиболее простых решения.

1. Допустим, метод вызывается при создании формы. Тогда определяем перегруженный конструктор второй формы:

1
2
3
4
5
6
private Form1 refForm;
public Form2(Form1 refForm)
{
    InitializeComponent();
    this.refForm = refForm;
}

Далее при вызове второй формы из первой передаем ссылку:

1
Form2 form = new Form2(this);

Готово. Осталось вызвать нужный метод. Но…

Что если Форма2 уже создана и показана пользователю и нужно сразу вызвать метод Формы1? Или возникает ситуация: Форма1 показывает Форму2, Форма2 показывает Форму3 и т.д., нужно вызвать из последней формы произвольный метод 1й формы? => Смотрим:

2. Определяем статическое свойство в классе формы, метод которой будем вызывать, и инициализируем его в конструкторе:

1
2
3
4
5
6
7
8
9
10
public static Form1 SelfRef
{
    get;
    set;
}

public Form1()
{
    SelfRef = this;
}

Наконец, в нужной форме (допустим Form3) выполняем нужный метод:

1
2
3
4
if(Form1.SelfRef != null)
{
    Form1.SelfRef.MyMethod();
}

P.S. По моему мнению, второй способ более удобен и гибок.

Иногда у программиста бывают моменты, когда хочется написать что-то “just for fun”. В данном посте таким примером послужит простое консольное приложение, которое строит множество Мандельброта из определенных символов.

Множество Мандельброта C#

Немного теории. Каждая позиция в изображение множества Мандельброта соответствует комплексному числу вида N = х + y*i, где х представляет вещественную часть, у— мнимую, а i — квадратный корень из -1. Координаты х и у позиции на изображении  соответствуют частям х и у в комплексном числе. Для каждой позиции в изображении выполняется проверка аргумента N, получаемого вычислением квадратного корня из х*х + у*у. Если его значение больше или равно 2, тогда считается, что позиция, соответствующая данному числу, имеет значение 0. Если же значение аргумента оказывается меньше 2, тогда оно заменяется значением N*N — N (дающим в результате N = (х*х — у*у — х) + B*х*у — у) *i) и снова подвергается проверке. Если это значение оказывается больше или равно 2, тогда считается, что позиция, соответствующая этому числу, имеет значение 1. И этот процесс  продолжается до тех пор, пока либо не будет присвоено значение позиции в изображении, либо не будет выполнено определенное количество итераций. На основании тех значений, что присваиваются каждой точке в изображении, в графической среде на экране отображался бы пиксель определенного цвета. Однако
поскольку в данном примере используется текстовый режим, вместо пикселей на экран выводятся символы.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
// Построение множества Мандельброта "just for fun".
using System;

class Program
{
    static void Main(string[] args)
    {
        double realCoord, imagCoord; // Мнимая и вещественные части числа N
        // Переменные для временного хранения информации во время вычислений
        double realTemp, imagTemp, realTemp2, arg;
        int iterations; // Кол-во итераций

        // Циклы for для циклической обработки охватывающих все изображение координат
        for (imagCoord = 1.2; imagCoord >= -1.2; imagCoord -= 0.05)
        {
            for (realCoord = -0.6; realCoord <= 1.77; realCoord += 0.03)
            {
                // Инициализируем некоторые переменные
                iterations = 0;
                realTemp = realCoord;
                imagTemp = imagCoord;
                arg = (realCoord * realCoord) + (imagCoord * imagCoord);

                // Цикл while для выполнения итерации
                while ( (arg < 4) && (iterations < 40))
                {
                    realTemp2 = (realTemp * realTemp) - (imagTemp * imagTemp) - realCoord;
                    imagTemp = (2 * realTemp * imagTemp) - imagCoord;
                    realTemp = realTemp2;
                    arg = (realTemp * realTemp) + (imagTemp * imagTemp);
                    iterations += 1;
                }

                /* После сохранения значения для текущей точки в iterations применяется
                 * оператор switch для выбора символа, выводимого на экран. Здесь используются только 4
                 * разных символа вместо 40 возможных, а также операция % для того, чтобы значения 0,
                 * 4, 8 и т.д. давали один символ, значения 1, 5, 9 и т.д. — другой и далее в том же духе */

                switch (iterations % 4)
                {
                    case 0:
                        Console.Write (".") ;
                        break;
                    case 1:
                        Console.Write("o");
                        break;
                    case 2:
                        Console.Write("O");
                        break;
                    case 3:
                        Console.Write("@");
                        break;
                }
            }
            Console.Write("\n");
        }
        Console.ReadKey();
    }
}

Различают два вида многозадачности: с ориентацией на процессы и с ориентацией на потоки. Важно понимать различия между ними.

Процесс (Process) по сути представляет собой выполняемую программу. Следовательно, многозадачность, ориентированная на процессы – средство, позволяющее выполнять две или более программ одновременно. В процессно-ориентированной многозадачности программа является наименьшим элементом кода, который может манипулироваться планировщиком задач.

Нити (Threads) — управляемые единицы выполняемого кода в пределах одного процесса. Все процессы имеют по крайней мере одну нить. Процесс ничего не исполняет, он просто служит контейнером для нитей.

P.S. Что должен знать правильный .NET-разработчик

В последних версиях Visual Basic и C# можно определять переменные без явного указания их типа данных (компилятор это делает за вас). При этом преимущества строго типизированных переменных остаются. Такой процесс называется выведением локального типа (local type inference) или неявным типизированием (implicit typing).

Например, создаем и инициализируем переменную типа String:

1
string str = “Hello!;

Благодаря выведению типа описательная часть декларации нам не нужна. Компилятор сам определит, что необходима строка и строго типизирует переменную. Это происходит при помощи ключевого слова var. Не путайте его с одноименным оператором в языке JavaScript (язык слабо типизированный). Переменные, определенные как var, будут строго типизированы:

1
var str = “Hello!;

В итоге получаем экономию нажатия клавиш, а так же все преимущества переменных с ранним связыванием.

Однако…Есть несколько вещей, которые необходимо знать при использовании выведения типа:

  1. Вашей локальной переменной для типизации компилятором должно быть присвоено значение (инициализация). В противном случае переменная не используется.
  2. Выведение типа работает только с локальными типами. Оно не работает с переменными уровня класса (поля) или статическими переменными. В этих случаях сгенерируется ошибка компилятора языка C#.

P.S. На мой взгляд, единственным недостатком неявного типизирования является ухудшение читаемость кода. Хотя, как говорится, на вкус и цвет…

P.S. Те разработчики, которые активно пользуются плагином Resharper, заметят что он активно предлагает использовать новые возможности компилятора по типизации.


Страница 1 из 41234

© 2009 PodCode – IT-заметки | Powered by Wordpress