В .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(); }
Комментариев нет:
Отправить комментарий