Вопрос по c#, metadata, mef, attributes – MEF GetExports <T, TMetaDataView> ничего не возвращает с AllowMultiple = True

5

Я не очень хорошо понимаю 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: & quot; MyNamespace.IMyInterface & quot ;.Metadata также правильно загружен в мой экспорт.

Если я удалюAllowMultiple сеттер и включает только один экспортируемый атрибут,myExports переменная теперь имеет единственный экспорт с загруженными метаданными.

Что я делаю неправильно?

EDIT: If I use weakly typed Metadata, my export is suddenly satisfied:

var myExports = CompositionContainer.GetExports<IMyInterface, IDictionary<string, object>>();

Есть идеи почему?

Ваш Ответ

1   ответ
9

Известно, что 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>();
Да, это то, что я закончил, прочитав следующую статью:blogs.microsoft.co.il/blogs/bnaya/archive/2010/01/29/… Я собирался опубликовать это вчера, но меня втянули в другие вещи, прежде чем я смог закончить, так что наслаждайтесь своими очками! sohum
Нет необходимости заставлять класс наследовать отAttribute скорее, чемExportAttribute, ТочкаMetadataAttributeAttribute это краткость и краткость ;-). Мне достаточно просто использовать собственное представление метаданных и вручную работать с массивами. Из документации не очевидно, чтоAllowMultiple заставляет записи метаданных становиться массивами, поэтому странно & # x2026;

Похожие вопросы