Почему MEF2 не применяет атрибуты метаданных ко всем экспортам деталей?

Я пытаюсь перенести коллекцию приложений на основе.NET Framework на.NET Core, и в рамках этого процесса мне нужно переключиться с использования MEF1 на MEF2. У меня были большие трудности, когда я размышлял над проблемами, связанными с MEF2 (хотя я нашел этот пост действительно полезным), но недавно я наткнулся на причину одного из них, который у меня возник.

В частности, у меня есть несколько классов, которые экспортируют метаданные с использованием пользовательских ExportAttribute и я хотел бы импортировать их все в другой класс и фильтровать их на основе этих метаданных. Все это работало нормально в MEF1, но в MEF2 я столкнулся с такими проблемами, как "Экспорт метаданных для x отсутствует, и значение по умолчанию не было предоставлено".

Более конкретно, я аннотирую свои экспортированные классы, как показано ниже:

[Export(typeof(IClientRequestProcessor<RelaySystemModel>))]
[TargetDevice("<<Foo>>")]
internal class RelaySystemClientRequestProcessor : IClientRequestProcessor<RelaySystemModel>
{
}

Затем в другом месте я попытаюсь импортировать их так:

[ImportMany]
public IEnumerable<ExportFactory<IClientRequestProcessor<RelaySystemModel>, DeviceSpecific>> RelayRequestProcessors { private get; set; }

А затем, при удовлетворении импорта, попытайтесь отфильтровать их по метаданным:

private static IEnumerable<ExportFactory<T, DeviceSpecific>> FilterForFoo<T>(IEnumerable<ExportFactory<T, DeviceSpecific>> items)
{
    return from it in items where it.Metadata.DeviceId == "<<Foo>>" select it;
}

куда TargetDeviceAttribute определяется следующим образом:

[MetadataAttribute, AttributeUsage(AttributeTargets.Class)]
public class TargetDeviceAttribute : ExportAttribute, IDeviceSpecific
{
    public TargetDeviceAttribute(string deviceId)
    {
        this.DeviceId = deviceId;
    }

    public string DeviceId { get; private set; }
}

Я обнаружил, что происходит то, что часть RelaySystemClientRequestProcessor соответствует двум экспортам: IClientRequestProcessor<RelaySystemModel>- это интересующий меня экспорт и интерфейс, с которым я пытаюсь импортировать деталь, и RelaySystemClientRequestProcessor, Однако метаданные "DeviceId" связаны только с последним, а не с первым, что бесполезно.

MEF2-экспорт

Я полагаю, что это можно решить несколькими способами, хотя я еще не полностью протестировал:

  1. Применение атрибута ExportMetadata("DeviceId", "<<foo>>") на все мои экспортируемые части.

  2. Изменение TargetDeviceAttribute использовать конструктор public TargetDeviceAttribute(string deviceId, Type exportType) : base(exportType),

Я не за эти решения; первый будет проблематичным, если я захочу изменить ключ метаданных, и оба будут связаны с изменением способа экспорта всех моих деталей.

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

1 ответ

Решение

Оказывается, мне просто нужно было удалить 6 символов. Вместо того, чтобы делать TargetDeviceAttribute наследовать от ExportAttribute, он должен просто наследовать от Attribute вместо:

[MetadataAttribute, AttributeUsage(AttributeTargets.Class)]
public class TargetDeviceAttribute : Attribute, IDeviceSpecific
{
    public TargetDeviceAttribute(string deviceId)
    {
        this.DeviceId = deviceId;
    }

    public string DeviceId { get; private set; }
}

В более общем случае это означает, что любые метаданные, которые могут быть связаны с несколькими возможными типами, но должны обеспечивать лучшую безопасность / поддерживаемость статического типа, чем просто ExportAttribute("foo", "bar") Должен ли я сделать что-то вроде ниже:

public interface IMetadataExtension
{
    string Foo { get; }
}

public class MetadataExtension : IMetadataExtension
{
    public string Foo { get; set; }
}

[MetadataAttribute]
public class MetadataExtensionAttribute : Attribute, IMetadataExtension
{
    public MetadataExtensionAttribute(string foo)
    {
        Foo = foo;
    }

    public string Foo { get; }
}

[Export]
[MetadataExtension("bar")]
public class SomeExport
{

}
Другие вопросы по тегам