Опираясь на ответ @ my, я думаю, что иметь общий интерфейс - это лучший дизайн, который вы можете использовать.Это самый простой способ использовать общий набор операций, которые вы можете применить к своим плагинам.Однако я хотел бы рассмотреть небольшое уточнение:
public interface IPlugin : IDisposable
{
void Initialise();
}
Благодаря реализации метода Dispose
ваша деталь может автоматически контролироваться функциями управления сроком службы CompositionContainer
.Весь ваш код выгрузки может быть введен туда, вот пример плагина:
public interface ILogger : IPlugin
{
void Log(string message);
}
[Export(typeof(ILogger))]
public class ConsoleLogger : ILogger
{
void IPlugin.Initialise()
{
Console.WriteLine("Initialising plugin...");
}
public void Log(string message)
{
Console.WriteLine(message);
}
public virtual void Dispose(bool disposing)
{
if (disposing)
{
Console.WriteLine("Disposing plugin...");
}
}
public void Dispose()
{
Dispose(true);
GC.SuppressFinalize(this);
}
}
Шаблон Dispose
позволяет стандартизировать механизм очистки вашего кода.Ваш экземпляр CompositionContainer
будет отслеживать этот элемент и очищать его при удалении.
Теперь я хотел бы описать приятное дополнение в MEFContrib , которое называется InterceptingCatalog.Этот каталог позволяет вам делать это, используя стратегии перехвата регистров, которые могут дать вам доступ к экспортированному значению до того, как оно будет возвращено в ваш код вызова.Одним из таких применений может быть автоматическое обеспечение вызова Initialise
на базовом интерфейсе IPlugin
при первом экспорте экземпляра:
public class InitialisePluginStrategy : IExportedValueInterceptor
{
public object Intercept(object value)
{
var plugin = value as IPlugin;
if (plugin != null)
plugin.Initialise();
return value;
}
}
Давайте свяжем все это:
static void Main(string[] args)
{
var catalog = new AssemblyCatalog(typeof(Program).Assembly);
var configuration = new InterceptionConfiguration()
.AddInterceptor(new InitialisePluginStrategy());
var interceptingCatalog = new InterceptingCatalog(catalog, configuration);
var container = new CompositionContainer(interceptingCatalog);
var logger = container.GetExportedValue<ILogger>();
logger.Log("test");
Console.ReadKey();
}
Если вы запустите это, вы заметите, что наш ConsoleLogger
автоматически инициализируется при первом получении его из контейнера.Нам не нужно беспокоиться о том, что он будет инициализирован снова, он будет делать это только тогда, когда создает экспортируемый экземпляр, что означает, что он подчиняется сценариям синглтона и не синглтона.
Выв этот момент может показаться, что это может быть излишним, но на самом деле это довольно элегантное решение, позволяющее автоматически запускать и утилизировать ваши детали, когда они больше не нужны.
Конечно, если вы хотите мелкозернистыйконтролировать, как инициализируются ваши части, вы можете просто управлять ими в методе, который вы пишете сами, вам просто нужно учитывать состояние плагина, когда вы это делаете.
Подробнее о InterceptingCatalog вы можете прочитать в Блог Петра Влодека