Можно ли параметризовать импорт MEF? - PullRequest
4 голосов
/ 15 апреля 2010

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

Допустим, у меня есть класс, который импортирует детали 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;
    }

}

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

public class MyViewModel {

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

}

public class MyOtherViewModel {

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

}

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

Ответы [ 2 ]

6 голосов
/ 15 апреля 2010

В руководстве по программированию 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 и использовать его при импорте и экспорте. Это просто и имеет тот же эффект, что и ограничение импорта. Однако этот подход не работает, если у вас есть несколько атрибутов метаданных и / или много возможных значений.

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

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

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

public ILoggerFactory
{
    ILogger Create(string category);
}

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

3 голосов
/ 15 апреля 2010

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

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

public class MyViewModel {

    private Logger log;

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

}
...