В .Net есть два варианта того, как сделать свои плагины: использование Microsoft Enterprise Library и использование отражений (reflection). Первый способ не совсем тривиальный и дня него нужно дополнительно скачивать MEL. Второй же способ доступен "из коробки" и, в большинстве ситуаций, его возможностей вполне достаточно.
Вообще, механизм отражений в .net - вещь достаточно мощная и интересная, так что, в будущем расскажу про него еще что-нибудь интересное. А пока переходим к плагинам.
Так как основа нашего механизма плагинов - отражение, то нам нужен какой-то базовый класс, который мы будет создавать при загрузке плагина. Так как кроме сигнатур предполагаемых методов с нашей стороны ничего больше не нужно, то идеальный вариант - создать интерфейс, поместив его в отдельную сборку (которую потом можно отдать сторонним разработчикам, которые будут делать плагины):
public interface IPluginDef
{
string SayHello();
}
Итак, что наследуя ваш интерфейс, насоздавали классов, наприсылали вам DLL'ек c ними и надо с этип добром теперь что-то делать. Для начала объявим где-нибудь в вашей программе глобальную переменную, в которой будут жить загруженные классы плагинов:
List< IPluginDef > all_plugins = new List< IPluginDef >();
А теперь самое интересное. Пишем метод загрузки плагина:
public bool LoadPlugin(string filePath)
{
if (!File.Exists(filePath)) return false;
Assembly PluginAssembly = null;
try
{
PluginAssembly = Assembly.LoadFrom(filePath);
}
catch
{
//сборка может быть не загружена по разным причинам,
//подробнее смотрите на MSDN: http://msdn.microsoft.com/ru-ru/library/1009fa28(v=vs.110).aspx
return false;
}
//В одной сборке может быть объявлено несколько типов.
Type[] allTypes = PluginAssembly.GetExportedTypes();
foreach (Type t in allTypes)
{
//Если t - класс и, в нашем случае, наследует IPluginDef
if (t.IsClass && typeof(IPluginDef).IsAssignableFrom(t))
{
try
{
//создаем класс
IPluginDef plugin = (IPluginDef)Activator.CreateInstance(t);
//и добавляем его в коллекцию плагинов
all_plugins.Add(plugin);
}
catch (MissingMethodException ex)
{
//Исключение может быть выброшено, если у типа нет конструктора по умолчанию
//на самом деле, CreateInstance умеет создавать классы и из конструкторов с параметрами
//а с помощью отражения можно узнать какие конструкторы есть в классе,
//но это уже тема для отдельного поста
}
}
}
return true;
}
Вот, в общем-то, и все. Теперь мы можем попросить все загруженные плагины поздороваться ;)
foreach (IPluginDef plugin in all_plugins)
{
plugin.SayHello();
}
Комментариев нет:
Отправить комментарий