Самая большая проблема, которую я имею до сих пор с MEF, состоит в том что, когда я составляю части в своей сменной обертке загрузчика, загружая полностью залоги, когда это находит проблему разрешения импорта с одним из блоков. Идеально, я хотел бы, чтобы ComposeParts показал своего рода, "игнорируют и продолжают" поведение, потому что идеальный пользовательский опыт повлек бы за собой загрузку как можно больше плагинов и просто входа события, когда определенному плагину не удается загрузиться. Я не смог найти информацию об этом в документации где угодно.
Если у Вас есть какие-либо другие предложения для того, как решить это, я слушаю!
В примере Вима есть основные идеи, но вместо того, чтобы тянуть контейнер напрямую, я бы посоветовал вам выполнить 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
}
}
}
Фактический плагин не будет создан, пока вы не нажмете .Value в первый раз, и именно тогда будут возникать ошибки, если у плагина есть ошибки в конструкторе или установщиках свойств импорта. Также обратите внимание, что я улавливаю исключение CompositionException, которое возникает из вызова .Value, если плагин делает что-то не так.
Вы можете использовать параметр 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
}
}
}