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, независимо от того, экспортировано ли в реализации имя контакта или нет?


person Jerry Bian    schedule 05.02.2015    source источник


Ответы (1)


Невозможно достичь того, чего вы хотите, с текущей реализацией IServiceLocator, предоставляемой Prism.

Переопределенный метод DoGetAllInstances() в этой реализации вызывает последнюю перегрузку метода GetExport():

this.compositionContainer.GetExports(serviceType, null, null);

Согласно MSDN, третий аргумент а

contractName: имя контракта объекта Lazy, которое нужно вернуть, или null или пустая строка ("") для использования имени контракта по умолчанию.

Как вы можете видеть в комментариях к этой теме:

Имя контракта по умолчанию является результатом вызова метода GetContractName для типа.

Это имя контракта по умолчанию основано на полном имени типа без каких-либо дополнительных ключей. Вот почему вы получаете только второй экспорт: он имеет имя контракта по умолчанию.

Таким образом, невозможно получить весь экспорт таким образом, не зная точно все ключи контракта.

Чтобы предоставить несколько экспортов, но при этом иметь возможность различать их, вы можете указать дополнительные метаданные для каждого экспорта и оставить одинаковые имена экспортных контрактов:

[Export(typeof(ITest))]
[ExportMetadata("Type", "MachineName")]
public class Test1 : ITest { }

[Export(typeof(ITest))]
[ExportMetadata("Type", string.Empty)]
public class Test2 : ITest { }
person dymanoid    schedule 24.02.2015