MEF GetExports<T, TMetaDataView> ничего не возвращает с AllowMultiple = True
Я не очень хорошо понимаю MEF, так что, надеюсь, это простое исправление того, как я думаю, что это работает.
Я пытаюсь использовать MEF, чтобы получить некоторую информацию о классе и о том, как его следует использовать. Я использую параметры метаданных, чтобы попытаться достичь этого. Мои интерфейсы и атрибут выглядят так:
public interface IMyInterface
{
}
public interface IMyInterfaceInfo
{
Type SomeProperty1 { get; }
double SomeProperty2 { get; }
string SomeProperty3 { get; }
}
[MetadataAttribute]
[AttributeUsage(AttributeTargets.Class, AllowMultiple = true)]
public class ExportMyInterfaceAttribute : ExportAttribute, IMyInterfaceInfo
{
public ExportMyInterfaceAttribute(Type someProperty1, double someProperty2, string someProperty3)
: base(typeof(IMyInterface))
{
SomeProperty1 = someProperty1;
SomeProperty2 = someProperty2;
SomeProperty3 = someProperty3;
}
public Type SomeProperty1 { get; set; }
public double SomeProperty2 { get; set; }
public string SomeProperty3 { get; set; }
}
Класс, украшенный атрибутом, выглядит следующим образом:
[ExportMyInterface(typeof(string), 0.1, "whoo data!")]
[ExportMyInterface(typeof(int), 0.4, "asdfasdf!!")]
public class DecoratedClass : IMyInterface
{
}
Метод, который пытается использовать импорт, выглядит следующим образом:
private void SomeFunction()
{
// CompositionContainer is an instance of CompositionContainer
var myExports = CompositionContainer.GetExports<IMyInterface, IMyInterfaceInfo>();
}
В моем случае myExports
всегда пусто В моем CompositionContainer у меня есть часть в моем каталоге, которая имеет два ExportDefinitions
как со следующим ContractName
: "MyNamespace.IMyInterface". Metadata
также правильно загружен в мой экспорт.
Если я удалю AllowMultiple
сеттер и включает только один экспортируемый атрибут, myExports
переменная теперь имеет единственный экспорт с загруженными метаданными.
Что я делаю неправильно?
РЕДАКТИРОВАТЬ: Если я использую метаданные со слабым типом, мой экспорт внезапно удовлетворяется:
var myExports = CompositionContainer.GetExports<IMyInterface, IDictionary<string, object>>();
Есть идеи почему?
1 ответ
Известно, что MEF имеет некоторые проблемы при работе с AllowMultiple = true
, Для полного объяснения вы можете, например, посмотреть здесь, в любом случае это происходит от того факта, что метаданные сохраняются в словаре, где значения являются массивами, когда AllowMultiple имеет значение true, и такая вещь не может быть отображена в вашем IMyInterfaceInfo.
Это обходной путь, который я использую. Прежде всего, ваш атрибут должен быть производным от Attribute, а не от ExportAttribute:
[MetadataAttribute]
[AttributeUsage(AttributeTargets.Class, AllowMultiple = true)]
public class ExportMyInterfaceAttribute : Attribute, IMyInterfaceInfo
{
public ExportMyInterfaceAttribute(Type someProperty1, double someProperty2, string someProperty3)
{
SomeProperty1 = someProperty1;
SomeProperty2 = someProperty2;
SomeProperty3 = someProperty3;
}
public Type SomeProperty1 { get; set; }
public double SomeProperty2 { get; set; }
public string SomeProperty3 { get; set; }
}
Это означает, что экспортируемый класс должен иметь 3 атрибута, стандартный экспорт и ваши пользовательские атрибуты:
[Export(typeof(IMyInterface))]
[ExportMyInterface(typeof(string), 0.1, "whoo data!")]
[ExportMyInterface(typeof(int), 0.4, "asdfasdf!!")]
public class DecoratedClass : IMyInterface
Затем вы должны определить представление для метаданных, которые будут импортированы. Это должен иметь конструктор, который принимает IDictionary в качестве параметра. Что-то вроде этого:
public class MyInterfaceInfoView
{
public IMyInterfaceInfo[] Infos { get; set; }
public MyInterfaceInfoView(IDictionary<string, object> aDict)
{
Type[] p1 = aDict["SomeProperty1"] as Type[];
double[] p2 = aDict["SomeProperty2"] as double[];
string[] p3 = aDict["SomeProperty3"] as string[];
Infos = new ExportMyInterfaceAttribute[p1.Length];
for (int i = 0; i < Infos.Length; i++)
Infos[i] = new ExportMyInterfaceAttribute(p1[i], p2[i], p3[i]);
}
}
Теперь вы сможете успешно звонить
var myExports = CompositionContainer.GetExports<IMyInterface, MyInterfaceInfoView>();