Почему 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" связаны только с последним, а не с первым, что бесполезно.
Я полагаю, что это можно решить несколькими способами, хотя я еще не полностью протестировал:
Применение атрибута
ExportMetadata("DeviceId", "<<foo>>")
на все мои экспортируемые части.Изменение
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
{
}