Механизм отражения, предоставляемый .NET, позволяет легко загружать плагины. В этой статье представлен метод, позволяющий гибко и корректно загружать необходимые плагины.
В .NET полное имя типа имеет формат «имя типа, имя сборки».
Например: «System.Configuration.NameValueSectionHandler, System, Version=1.0.3300.0, Culture=neutral, PublicKeyToken=b77a5c561934e089».
Имя типа: System.Configuration.NameValueSectionHandler — полное имя типа с пространством имен.
Вы также можете получить полное имя, используя тип.
Например: строка typeName = typeof(NameValueSectionHandler).FullName;
Имя сборки: «Система, версия = 1.0.3300.0, культура = нейтральная, PublicKeyToken = b77a5c561934e089»,
Сборка называется System, и система автоматически адаптирует ее расширение (например, System.dll или System.exe);
Версия, культура и PublicKeyToken — это конкретная версия, культурный фон и подпись сборки. Особых требований нет, и их можно опустить.
Мы можем динамически загружать требуемый тип на основе имени типа. нравиться:
string typeName = "System.Configuration.NameValueSectionHandler, System";
Тип t = Тип.GetType(имятипа);
Объект obj = Activator.CreateInstance(t);
//или
System.Configuration.NameValueSectionHandler obj = (System.Configuration.NameValueSectionHandler)Activator.CreateInstance(t);
На этом этапе obj является требуемым экземпляром типа.
Обычно плагины представляют собой классы, которым необходимо реализовать определенные интерфейсы. Поэтому перед загрузкой плагина необходимо определить, подходит ли тип плагина.
Например, если интерфейс плагина — IPlugin, мы можем идентифицировать его следующим образом:
строка InterfaceName = typeof(IPlugin).FullName;
string typeName = "Muf.MyPlugin, MyPlugin";
Тип t = Тип.GetType(имятипа);
если ( т == ноль
|| !t.IsClass
|| !t.IsPublic
|| t.GetInterface(имяинтерфейса) == ноль)
{
return null // Не нужный плагин;
}
Обобщая приведенный выше код, мы можем составить общий код загрузки плагинов:
/**//// <сводка>
/// Динамически загружаем и создаем тип с указанным интерфейсом
/// </сводка>
/// <param name="className">Имя типа</param>
/// <param name="interfaceName">Указанное имя интерфейса</param>
/// <param name="param">Укажите параметры конструктора (нулевой или пустой массив означает вызов конструктора по умолчанию)</param>
/// <returns>Возвращает созданный тип (нуль означает, что тип не может быть создан или не найден)</returns>
общедоступный статический объект LoadObject (строковое имя класса, строковое имя интерфейса, параметр объекта [])
{
пытаться
{
Тип t = Type.GetType(имякласса);
если ( т == ноль
|| !t.IsClass
|| !t.IsPublic
|| т.IsAbstract
|| t.GetInterface(имяинтерфейса) == ноль)
{
вернуть ноль;
}
Объект o = Activator.CreateInstance(t, param);
если ( о == ноль )
{
вернуть ноль;
}
вернуться о;
}
поймать (исключение ex)
{
вернуть ноль;
}
}
Позже мы можем использовать LoadObject для загрузки любых необходимых плагинов.
Плагины обычно помещаются в файлы конфигурации и считываются программой:
Примеры файлов конфигурации (см. мои соответствующие статьи об использовании файлов конфигурации):
<?xml version="1.0"coding="utf-8" ?>
<конфигурация>
<конфигурационные секции>
<section name="Каналы" type="Vmp.Configuration.ChannelsSectionHandler, Связь" />
</configSections>
<Каналы>
<канал
ChannelType="Vmp.Communication.TcpChannel, Связь"
TraceFile="d:logchannel1.log"
Port="2020" MaxConnections="300" BufferSize="2048"
/>
</Каналы>
</конфигурация>
Пример кода:
частный ArrayListchannelsList = новый ArrayList();
частный LoadChannels();
{
ArrayList каналыConfig = (ArrayList)ConfigurationSettings.GetConfig("Каналы");
foreach (конфигурация хэш-таблицы в ChannelConfig)
{
строка ChannelType = (строка) config["ChannelType"];
IChannel канал = (IChannel) CommonUtils.LoadObject(channelType, typeof(IChannel).FullName, новый объект[]{config});
если (канал == ноль)
продолжить
список каналов.Добавить(канал);
}
Вы также можете пройти по указанному каталогу плагинов и загрузить все плагины, соответствующие требованиям, например:
public IPlugin[] LoadAllPlugIn(string pluginDir)
{
//Установим каталог плагина по умолчанию
if(pluginDir == null || PluginDir == "")
pluginDir = "./PlugIns"
// Получаем имя интерфейса плагина
string InterfaceName = typeof(IPlugin).FullName
// Массив, используемый для хранения плагинов;
ArrayList arr = new ArrayList();
// Проходим каталог плагина (при условии, что плагин представляет собой dll-файл)
foreach(строковый файл в Directory.GetFiles(pluginDir, "*.dll"))
{
//Загружаем файл плагина
Сборка asm = Сборка.LoadFile(файл);
// Обходим экспортированные классы плагинов
foreach (Введите t в asm.GetExportedTypes())
{
//Загрузить плагин, если плагин не соответствует указанному интерфейсу, вернуть ноль.
Плагин IPlugin = LoadObject(t.FullName,interfaceName, null) как IPlugin
if(plugin!= null)
arr.Add(плагин);
}
}
// Возврат к плагину
return (IPlugin[])arr.ToArray(typeof(IPlugin));
}