Можно ли параметризовать импорт MEF?

Я относительно новичок в MEF, поэтому я не полностью понимаю его возможности. Я пытаюсь добиться чего-то похожего на Unity InjectionMember.

Допустим, у меня есть класс, который импортирует части MEF. Для простоты возьмем следующий класс в качестве примера экспортируемой части.

[Export]
[PartCreationPolicy(CreationPolicy.NonShared)]
public class Logger {

    public string Category {
        get;
        set;
    }

    public void Write(string text) {
    }

}

public class MyViewModel {

    [Import]
    public Logger Log {
        get;
        set;
    }

}

Теперь я пытаюсь выяснить, можно ли указать значение свойства «Категория» при импорте. Что-то типа:

public class MyViewModel {

    [MyImportAttribute(Category="MyCategory")]
    public Logger Log {
        get;
        set;
    }

}

public class MyOtherViewModel {

    [MyImportAttribute(Category="MyOtherCategory")]
    public Logger Log {
        get;
        set;
    }

}

В настоящее время я реализую IPartImportsSatisfiedNotification и устанавливаю категорию в коде. Но, очевидно, я бы предпочел хранить все аккуратно в одном месте.


person Josh    schedule 14.04.2010    source источник


Ответы (2)


В руководстве по программированию MEF прочитайте раздел Экспорт и метаданные. Он показывает, как вы можете добавить метаданные к экспортируемой части либо с помощью атрибута ExportMetadata, либо путем определения собственного пользовательского атрибута экспорта.

Затем вы можете определить интерфейс ILoggerMetadata следующим образом:

public interface ILoggerMetadata
{
    string Catagory { get; }
}

и сделайте ImportMany из IEnumerable<Lazy<ILogger,ILoggerMetadata>> и выберите тот, который вы хотите, в коде следующим образом:

private ILogger fooLogger;

[ImportMany]
public IEnumerable<Lazy<ILogger,ILoggerMetadata>> Loggers
{
    set
    {
        this.fooLogger = value.First(x => x.Metadata.Catagory == "foo").Value;
    }
}

Я согласен, что было бы лучше поместить ограничения метаданных прямо в атрибут импорта, но в настоящее время это невозможно в MEF из коробки. (Возможно, для этого можно расширить MEF.)

Другой подход состоит в том, чтобы получить интерфейс IFooLogger из ILogger и использовать его при импорте и экспорте. Это просто и по сути имеет тот же эффект, что и установка ограничения в импорте. Однако этот подход не работает, если у вас есть несколько атрибутов метаданных и/или много возможных значений.

редактировать: я слегка неправильно понял ваш вопрос; Я думал, что речь идет об ограничении импорта, а не о настройке импортированного объекта с некоторыми дополнительными параметрами.

Я думаю, что этот недавний пост Кэтлин Доллард о той же проблеме. Кроме того, в этой статье об отношениях между компонентами Николас Блумхардт моделирует такую ​​"параметризацию " отношение как инъекция Func<X,Y> (или Func<ILogger,string> в вашем случае).

Вы можете сделать то же самое в MEF, поместив атрибут [Export(typeof(Func<ILogger,string>))] непосредственно в метод. Или, если вам нужен менее двусмысленный контракт, вы можете определить интерфейс ILoggerFactory и импортировать/экспортировать его:

public ILoggerFactory
{
    ILogger Create(string category);
}

В конце концов, вам все равно придется вызывать фабрику в коде.

person Wim Coenen    schedule 15.04.2010
comment
Но если я правильно понимаю, это потребует от меня указать (при экспорте), какие категории есть. По сути, я хочу, чтобы импортер ввел свой собственный (не общий) экземпляр ILogger и декларативно указал его категорию. Но я не думаю, что в настоящее время у MEF есть точка расширения, позволяющая мне сделать это с моделью с атрибутами. В любом случае, похоже, мне придется сделать это в коде. - person Josh; 15.04.2010
comment
Хотя после публикации я понял, что, хотя мне все еще нужно делать это в коде, я мог бы установить категорию в сеттере, если бы использовал обычное свойство с поддержкой поля. Это по крайней мере лучше, чем делать это в IPartImportsSatisfiedNotification. - person Josh; 15.04.2010
comment
Хм, не могли бы вы выделить заводскую рекомендацию в отдельный ответ? Я хочу проголосовать за это, но не за что-то другое ;-). - person binki; 26.08.2016

После дальнейшего изучения MEF кажется, что нет способа сделать это декларативно. Хотя вы можете получить свои собственные атрибуты экспорта, похоже, не существует какого-либо механизма для получения атрибута импорта каким-либо осмысленным способом.

Но вместо реализации IPartImportsSatisfiedNotification я могу (теперь кажется очевидным) установить категорию в установщике. Я должен отказаться от автоматической собственности, но это жизнь.

public class MyViewModel {

    private Logger log;

    [Import]
    public Logger Log {
        get { return log; }
        set {
            log = value;
            log.Category = "MyCategory";
        }
    }

}
person Josh    schedule 15.04.2010
comment
Да, это примерно так же близко, как вы собираетесь добраться до того, что вы хотите. - person Wes Haggard; 15.04.2010
comment
Или использовать шаблон фабрики, где фабрика создается MEF, но сама фабрика управляет созданием экземпляров. Таким образом, вы можете избежать публично доступных для записи свойств, если хотите их избежать. - person binki; 26.08.2016