mef enum экспорт и архитектура - PullRequest
0 голосов
/ 12 сентября 2011

Я хочу, чтобы моя подсистема плагинов использовала mef, но у меня мало вопросов, потому что я новичок в csharp и mef (

Что я хочу сделать:

  1. каждый плагин можетсоздать свой собственный интерфейс IPlugin1, IPlugin2 ...
  2. каждый из этих интерфейсов должен иметь определенные функции Load, Unload
  3. , используя mef, я хочу перечислить все экспорты и вызвать Load / Unload

Вопросы:

а) Хорошее ли мое решение и если нет, как я могу улучшить его (используя что-то еще)?

б. Как перечислить все экспорты, используя mefи вызвать указанную интерфейсную функцию?

Буду признателен за все ссылки и критику. Спасибо за все.

Ответы [ 2 ]

1 голос
/ 12 сентября 2011

Опираясь на ответ @ 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 вы можете прочитать в Блог Петра Влодека

1 голос
/ 12 сентября 2011

Если вы хотите, чтобы все ваши интерфейсы плагинов привязывались к их собственному интерфейсу, вам следует предоставить интерфейс для их расширения:

public interface IMyInterface
{
    void Load();
    void Unload();
}

Затем, когда плагины создают свои собственные интерфейсы, они должныРасширение вашего общедоступного интерфейса:

public interface IPlugin1 : IMyInterface
{
    void DoPlugin1Func();
}

Теперь, чтобы получить коллекцию интерфейсов, экспортируемых в MEF, вы должны пометить свой интерфейс как InheritedExport:

[InheritedExport(typeof(IMyInterface))]
public interface IMyInterface { ... }

Это говорит о том, что любой класс, который каким-либо образом выходит из IMyInterface, будет экспортирован как тип IMyInterface, даже по дереву:

//This class will be exported as an IMyInterface
public class PluginImplementation1 : IPlugin1 { ... }

Наконец, где-то в вашем коде (где это применимо),вы можете импортировать коллекцию экземпляров IMyInterface.

public class SomeClass
{
    [ImportMany(typeof(IMyInterface))]
    private IEnumerable<IMyInterface> Plugins { get; set; }
}

Если все настроено правильно, Plugins будет перечислением классов, которые через наследование экспортируются как IMyInterface s.


Ресурсы:

...