ServiceLocator GetAllInstances не содержит экземпляр, имя контракта которого указано
Предположим, у меня есть интерфейс ITest
:
public interface ITest
{
void PrintMachineInfo();
}
И плюс две реализации:
[Export("MachineName", typeof(ITest))]
[PartCreationPolicy(CreationPolicy.Shared)]
public class Test1 : ITest
{
public void PrintMachineInfo()
{
Console.WriteLine(Environment.MachineName);
}
}
[Export(typeof(ITest))]
[PartCreationPolicy(CreationPolicy.Shared)]
public class Test2 : ITest
{
public void PrintMachineInfo()
{
Console.WriteLine(Environment.OSVersion);
}
}
Затем я попытался получить все экземпляры ITest
:
var foo = ServiceLocator.Current.GetAllInstances<ITest>();
foreach (var test in foo)
{
test.PrintMachineInfo();
}
Оказывается, что только экземпляр Test2
могут быть возвращены. Из-за названия контракта он просто не может найти экземпляр Test1
,
Я использую MEF + ServiceLocator + MefAdapter для запуска всех этих вещей. Из моей отладки MefAdapter переписал метод DoGetAllInstances(Type serviceType)
в ServiceLocatorImplBase
, но он предоставляет только один параметр serviceType
,
Итак, как можно получить все экземпляры ITest
с ServiceLocator, независимо от того, было ли в реализации экспортировано имя контакта или нет?
1 ответ
Невозможно достичь того, чего вы хотите, с текущей реализацией IServiceLocator
это обеспечивается Призмой.
Переопределенный DoGetAllInstances()
метод в этой реализации вызывает последнюю перегрузку GetExport()
метод:
this.compositionContainer.GetExports(serviceType, null, null);
Согласно MSDN, третий аргумент
contractName: имя контракта объекта Lazy, который нужно вернуть, либо ноль, либо пустая строка ("") для использования имени контракта по умолчанию.
Как вы можете видеть в комментариях к этой теме:
Имя контракта по умолчанию является результатом вызова метода GetContractName для типа.
Имя контракта по умолчанию основано на полном имени типа без каких-либо дополнительных ключей. Вот почему вы получаете только второй экспорт: он имеет имя контракта по умолчанию.
Таким образом, невозможно получить весь экспорт таким образом, не зная точно все ключи контракта.
Чтобы обеспечить несколько экспортов при возможности их различения, вы можете предоставить дополнительные метаданные для каждого экспорта и оставить одинаковые имена контрактов на экспорт:
[Export(typeof(ITest))]
[ExportMetadata("Type", "MachineName")]
public class Test1 : ITest { }
[Export(typeof(ITest))]
[ExportMetadata("Type", string.Empty)]
public class Test2 : ITest { }