C#

О блоге

Рейтинг
0.00
голосов: 0
Практика программирования на C#. Методы, советы, секреты…

Администраторы (1)

Модераторы (0)

Модераторов здесь не замечено

Читатели (1)

C#

Преобразовать строку в делегат в C#

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

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

Я не буду рассказывать то как я думал, чтобы дойти до результата, а сразу его представлю. Итак, использование моего класса выглядит следующим образом:

// объявляем требуемый делегат. Он может иметь любые принимаемые параметры и возвращаемое значение
public delegate Single	TestDelegate( Single param1, Single param2 );

// строка, в которой записан текст функции. В примере это будет очень простой код. В реальности он может быть любым.
String funcText = "public static Single	FuncName( Single param1, Single param2 )"+
		"{"+
		"	return param1 + param2;"+
		"}";

// Создаем функцию, передавая имя создаваемой функции и строку ее содержащую.
// Кроме того, параметром шаблона передается тип делегата, объявленный ранее
TestDelegate func = DelegateGenerator.CreateDelegate< TestDelegate >( "FuncName", funcText );

// проверяем, получилось ли создать делегат
if( null == func )
	return;

// работаем как с обычной функцией
Single ss = func( 5, 10 ); // ss = 15


Если вам интересно, как же все это работает, то читайте дальше!


Читать дальше
C#

Создание системы конфигурирования приложения в C#. Паттерн "первокласный ключ".

Существует множество способов сохранения данных приложения для их повторного использования при следующем старте. Какой именно вы выберите (хранение данных в базе, в файле конфигурации, в реестре и т.п) не имеет значения. Это зависит от специфики приложения. Однако остается вопрос — как с этим работать программисту в коде. Работа должна быть максимально простой и надежной. В этой статье будут показаны типичные решения и проблемы с ними связанные, а так же будет представлено решение на основе паттерна «Первокласный ключ». Предложенный подход значительно эффективнее, функциональнее и хорошо масштабируем. Он пригоден для модульных приложений, которые могут распространяться в различных конфигурациях. Подход, который он использует пригоден для решения многих задач. Обо всем этом смотри под катом.



Читать дальше
C#

Написание компактного и эффективного кода в C#

Языковые средства не стоят на месте и сегодня C# позволяет писать многие вещи более компактно, чем это выглядело бы в C++. Для этого используются делегаты, лямбда функции и алгоритмы пакетной обработки данных. В статье будут рассмотрены наиболее типичные задачи и их решения, которые позволят сделать ваш код более компактным, понятным и эффективным.



Читать дальше
C#

Проблема событий при редактировании компонентов из кода в WinForms

При работе с интерфейсом WinForms в C# часто появляется проблема с событиями компонентов. Проблема заключается в следующем: Если редактировать содержимое компонента из кода (например указать текущий выбранных элемент в ComboBox), то приходит событие об изменении содержимого, от этого компонента. Событие конечно правильно приходит, вот только реагировать на него не нужно и иногда даже вредно. Так же подписка на события может привести к рекурсивному вызову функции, который переполняет стек. Один из вариантов решения проблемы я представляю в этой статье.

Пример проблемы


Этот пример один из многих. Код написан так, чтобы было понятно суть проблемы. Допустим на форму добавлено несколько компонентов NumericUpDown, через которые идет редактирование полей некоторого класса. Так выглядит код инициализации компонентов:


private void	Init()
{
	numericCtrl1.Value = someClass.Valu1;
	numericCtrl2.Value = someClass.Valu2;
	numericCtrl3.Value = someClass.Valu3;
}


Так же добавлена реакция на действия пользователя, в виде подписи на событие ValueChanged у каждого NumericUpDown компонента. Причем при изменение любого из контролов вызывается одна и та же функция.


private void	OnInfoChanged(object sender, EventArgs e)
{
	someClass.Valu1 = numericCtrl1.Value;
	someClass.Valu2 = numericCtrl2.Value;
	someClass.Valu3 = numericCtrl3.Value;
	someClass.Regenerate();
}


Код логически верен. Проблема в том, что в функции Init трижды инициирует событие ValueChanged и будет вызываться функция OnInfoChanged. Это во-первых, перетрет содержимое класса someClass, и приведет его в невалидное состояние, а во-вторых, трижды вызовется функция Regenerate, которая может быть весьма ресурсоемкой. В данной ситуации нужно как-то проигнорировать событие.

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

Есть еще решение — отписываться от обработчиков событий на время выполнения кода. Этот вариант так же плох тем, что затрудняет читаемость кода, нужно писать комментарии для всего этого. Кроме того легко забыть или не верно зарефакторить обратную подписку на событие. Например добавить return в функцию, перед подпиской. Такие ошибки очень сложно заметить и искать.

Более универсальное решение, убирающее потенциальные ошибки, смотри под катом.


Читать дальше
C#

Оптимизация C# кода. Создание класса ObjectPool

Поскольку в C# используется управляемая сборка мусора, то нет возможностей контролировать создание, размещение и удаление объектов. Однако часто мы работаем с большим количеством повторяющихся данных, создаем и уничтожаем одинаковые объекты. В таких случаях следует работать не с объектами в отдельности, а с их множеством.

Например, когда пользователь попросил отобразить список каких то элементов, то вы заполняете TreeView определенными данными. Затем пользователь просит отобразить другие элементы, TreeView очищается и заполняется заново. Потом еще и еще раз. При этом идет постоянное создание и уничтожение объектов. Это не эффективно с точки зрения производительности, т.к. выделение и освобождение памяти с конструированием сложных объектов — это долгая операция (ни считая сборки мусора, которая так же занимает время).

Значительно рациональнее было бы повторно использовать уже созданные объекты. Это позволит единожды выделить все необходимые ресурсы и работать с ними. Это решит проблемы, описанные ранее. Именно о том, как создать такой ObjectPool и пойдет речь в данной статье.


Читать дальше
C#

Оптимизация C# кода. Работа с ресурсами сборки.

Если вам нужно множеству объектов передать один и тот же объект Image, который лежит у вас в качестве ресурсов сборки, то нужно сначала его создать, а затем передавать всем объектам. Не в коем случае на получать его из ресурсов для каждого объекта. Это можно проиллюстрировать на примере.


Так не надо (время выполнения: 4.633 секунды + OutOfMemory при количестве 250000):
List< Image > l1 = new List< Image >();
for( int i = 0; i < 25000; ++i )
	l1.Add( Properties.Resources.help );

Надо так (время выполнения: 0 секунд (меньше миллисекунды)):
Image img = Properties.Resources.help;
List< Image > l2 = new List< Image >();
for( int i = 0; i < 25000; ++i )
	l2.Add( img );


Это происходит по тому, что при каждом указании Properties.Resources.help происходит создание нового объекта Image, инициализация новой области памяти. Во втором же случае происходит копирование ссылки на один и тот же объект. Это важно понимать, что если вы захотите модифицировать картинку, то вероятно вам нужно еще раз загрузить ресурс, чтобы эта картинка не изменилась во всех местах ее использования. При взятии элемента из ресурсов вызывается такой код:


(Bitmap) ResourceManager.GetObject("help", resourceCulture);


То же самое происходит при работе с другими типами ресурсов.

Читайте другие статьи по оптимизации кода в C#:
Создание класса ObjectPool
C#

Скрытие WinForms окна

Иногда при создание Windows Forms приложения требуется скрывать окно, когда пользователь его закрывает. Действие по умолчанию — это закрытие окна. При этом высвобождаются все ресурсы и доступ к данном окну после его закрытия приведет к ошибке.

Для того чтобы скрывать окно без его уничтожения нужно подписаться на событие FormClosing и написать там следующее:


private void MainWindow_FormClosing(object sender, FormClosingEventArgs e)
{
	Hide();
	e.Cancel = true;
}


При закрытие пользователем окна оно будет сохранено в памяти и его можно будет повторно отобразить на экране.

Будьте внимательны, если это главное окно приложения, т.е. при его закрытии приложение продолжит работать и станет невидимо для пользователя. Тем не менее оно будет расходовать ресурсы системы.
C#

Как подписать C# сборку строгим именем. Использование sn.exe

.Net Framework поддерживает два вида сборок: с не строгим именем (weakly named assemblies) и со строгим именем (strong named assemblies). Они отличаются только тем, что вторые подписаны при помощи пары ключей разработчика, которые однозначно идентифицируют сборку. Подписание сборки особенно актуально если она будет использоваться разными приложениями и просто необходима, если она будет размещаться в GAC (global assembly cache)

Поскольку такие сборки однозначно идентифицируются, то это повышает ее безопасность, т.к. нельзя просто подменить библиотеку. Программа будет искать сборку по строгому имени.

Рассмотрим как можно подписать свою C# библиотеку.


Читать дальше
C#

Как подписать существующую dll строгим именем

Иногда приходится использовать сторонние библиотеки в своем приложении. Если вы хотите подписать свои библиотеки строгим именем при помощи *.snk / *.pfx ключей, то Visual Studio потребует чтобы все используемые библиотеки были подписаны. В случае если вы используете стороннюю библиотеку которая не подписана и к коду которой у вас нет доступа, то вам придется самим подписать ее. Это можно сделать следующим образом.


Читать дальше
C#

Интеграция Native кода в C# проект

Сегодня стала очень популярной платформа .Net Framework и язык C#. На ней пишутся приложения, игры, инструменты. Однако существует много кода написанного на C++, который часто нужно использовать в C# проектах.

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

В этой статье речь пойдет о том, как интегрировать Native код в C# проект и успешно его развивать. В качестве IDE будет использоваться Microsoft Visual Studio.


Читать дальше