суббота, 6 марта 2010 г.

О пользе System.Reflection

Честно говоря, первый раз столкнувшись с рефлексией в .NET, я думал: "Ну это точно можно пролистать, вряд ли быстро пригодится!".

Все оказалось иначе, а все из-за...

Есть задача.

Некий Executor выполняет команды, идентифицируемые строковыми именами.

Понятно, чтобы выполнить запрос на экзекуцию :) команды по ее имени, нужно иметь какой-то словарь этих самых команд. Хорошо, заводим словарь и метод для его пополнения AddCommand(string, Command).

А вот теперь вопрос: кто, где и когда должен вызывать этот метод?
Ага, нет проблем! Ведь можно <здесь перечисление вариантов>!
Но проблема в том, что многие из этих вариантов будут лишены гибкости, а это, как показывает опыт, плохо (или по крайней мере не очень хорошо).

Теперь один из приемлемых, как по мне, вариантов решения.

Создаем атрибут CommandAttribute, наделяя его полем CommandName. Этот атрибут применяется ко всем потомкам абстрактного Command.

В конструктор класса Executor помещаем код, который:

1. Получает массив сборок текущего домена:
Assembly[] assemblies = AppDomain.CurrentDomain.GetAssemblies ();
2. Для каждого типа каждой сборки получает массив атрибутов:
CommandAttribute[] attributes = (CommandAttribute[])type.GetCustomAttributes (typeof(CommandAttribute), false);
3. Использует конструктор типа, если массив его атрибутов содержит нужный нам CommandAttribute, а также если тип унаследован от Command:
ConstructorInfo ctor = type.GetConstructor (new Type[] { typeof(string[]) });
AddCommand ((ICommand)ctor.Invoke (new object[] { commandAliases }));
Гибкость налицо: для создания новой команды необходимо просто унаследовать класс от абстрактного Command и добавить атрибут CommandAttribute - это все, больше ничего лишнего.

Комментариев нет:

Отправить комментарий