MEF CompositionContainer.ComposeParts - загрузка всего, что может быть решено, и игнорирование ошибок - PullRequest
5 голосов
/ 04 июня 2010

Самая большая проблема, с которой я столкнулся с MEF, заключается в том, что при компоновке деталей в оболочке загрузчика плагинов загрузка полностью выполняется, когда обнаруживается проблема разрешения импорта с одной из сборок. В идеале, я бы хотел, чтобы ComposeParts демонстрировал своего рода поведение "игнорировать и продолжить", потому что идеальный пользовательский опыт подразумевал бы загрузку как можно большего количества плагинов и простую запись события, когда конкретный плагин не загружался. Мне нигде не удалось найти информацию об этом в документации.

Если у вас есть другие предложения, как это решить, я слушаю!

Ответы [ 2 ]

10 голосов
/ 04 июня 2010

Пример Wim имеет основные идеи, но вместо того, чтобы тянуть контейнер напрямую, я бы посоветовал вам сделать Lazy ImportMany следующим образом:

[Export]
public class MyApplication
{
   [ImportMany(typeof(IPlugin))]
   public IEnumerable<Lazy<IPlugin>> Plugins { get; set; }
}

Затем вы можете инициализировать плагины один за другим и отлавливать любые ошибки, например:

void InitializePlugins()
{
   foreach (Lazy<IPlugin> plugin in Plugins)
   {
       try
       {
          plugin.Value.Initialize();
       }
       catch (CompositionException e)
       {
          // Handle the error accordingly
       }
   }   
}

Фактический плагин не будет создан, пока вы не включите. Значение в первый раз, и именно тогда произойдут ошибки, если плагин имеет ошибки в конструкторе или установщиках свойств импорта. Также обратите внимание, что я улавливаю исключение CompositionException, которое будет исходить из вызова .Value, если плагин что-то делает не так.

2 голосов
/ 04 июня 2010

Вы можете использовать параметр AllowDefault. Установка его в true при импорте приведет к зависимости null, если ни одна доступная деталь не сможет удовлетворить импорт.

public class MyComponent
{
    [Import(AllowDefault=true)]
    public IMyDependency MyDependency { get; set; }
}

Чтобы загрузить все доступные плагины, но игнорировать те, которые не могут быть загружены из-за отсутствующих частей, [ImportMany] уже сделает то, что вы хотите по умолчанию:

[Export]
public class MyApplication
{
   [ImportMany(typeof(IPlugin))]
   public IEnumerable<IPlugin> Plugins { get; set; }
}

Обратите внимание, что вышеупомянутые методы только устраняют ошибки композиции, которые вызваны отсутствующими частями. Если деталь и ее импорт действительно доступны, но при вызове конструктора она вызывает непредвиденные исключения, вы все равно получите исключение. Чтобы игнорировать такие проблемы, которые не связаны с композицией, вы можете вызвать контейнер напрямую следующим образом:

IEnumerable<IPlugin> GetPluginsFromContainer(CompositionContainer container)
{
   foreach (Lazy<IPlugin> pluginExport in container.GetExports<IPlugin>())
   {
       try
       {
          yield return pluginExport.Value;
       }
       catch (Exception e)
       {
          // report failure to instantiate plugin somewhere
       }
   }   
}
...