Составление частей MEF в C# как простой контейнер Funq

В Funq и, вероятно, в большинстве других IoC-контейнеров я могу просто сделать это для настройки типа:

container.Register<ISomeThing>(c => new SomeThing());

Как я могу быстро расширить MEF (или использовать существующие функции MEF), чтобы сделать то же самое без использования атрибутов.

Вот как я думал, что смогу это сделать:

var container = new CompositionContainer();
var batch = new CompositionBatch();
batch.AddExport<ISomeThing>(() => new SomeThing());
batch.AddExportedValue(batch);
container.Compose(batch);

С этим методом расширения для CompositionBatch:

public static ComposablePart AddExport<TKey>(this CompositionBatch batch, Func<object> func)
{
    var typeString = typeof(TKey).ToString();
    return batch.AddExport(
        new Export(
            new ExportDefinition(
                typeString, 
                new Dictionary<string, object>() { { "ExportTypeIdentity", typeString } }),
            func));

}

Если я позже сделаю:

var a = container.GetExport<ISomeThing>().Value;
var b = container.GetExport<ISomeThing>().Value;

Оба экземпляра одинаковы. Как я могу заставить (настроить) их для разных экземпляров?

Если это не тот путь, как бы я сделал это в MEF?

4 ответа

Если вы не хотите использовать атрибуты, вы можете использовать этот трюк (на основе поста Марка Симанна).

Сначала создайте универсальный класс, подобный этому:

[PartCreationPolicy(CreationPolicy.NonShared)]
public class MefAdapter<T> where T : new()
{
    private readonly T export;

    public MefAdapter()
    {
        this.export = new T();
    }

    [Export]
    public virtual T Export
    {
        get { return this.export; }
    }
}

Теперь вы можете зарегистрировать любой класс в контейнере, например:

var registeredTypesCatalog = new TypeCatalog(
    typeof(MefAdapter<Foo>),
    typeof(MefAdapter<Bar>), 
    ...);
var container = new CompositionContainer(catalog);

В качестве альтернативы, вы можете реализовать свой собственный поставщик экспорта, полученный из ExportProvider, который позволяет вам в значительной степени дублировать способ работы Funq:

var provider = new FunqyExportProvider();
provider.Register<IFoo>(context => new Foo());
var container = new CompositionContainer(provider);

Я хотел бы представить, что ключом является добавление делегата в контейнер, например:

container.AddExportedValue<Func<ISomething>>(() => new Something());

Таким образом, вы можете получить делегат и выполнить его:

var factory = container.GetExport<Func<ISomething>>();
ISomething something = factory();

Конечно, MEF (Silverlight) действительно обеспечивает нативный ExportFactory<T> (а также ExportFactory<T,TMetadata> тип, который поддерживает создание новых экземпляров для каждого вызова импорта. Вы можете добавить поддержку для этого, загрузив библиотеку Glen Block ExportFactory для.NET 4.0 (Desktop).

Оба экземпляра одинаковы. Как я могу заставить (настроить) их для разных экземпляров?

Просто отметьте SomeThing класс как это:

[Export(typeof(ISomeThing)]
[PartCreationPolicy(CreationPolicy.NonShared]
public class SomeThing : ISomeThing
{
   ...
}

И тогда вы получите разные экземпляры, куда бы вы ни импортировали ISomeThing,

Кроме того, вы также можете установить необходимую политику создания для импорта:

[Export(typeof(IFoo))]
public class Foo : IFoo
{
   [Import(typeof(ISomeThing), 
       RequiredCreationPolicy = CreationPolicy.NonShared)]
   public ISomething SomeThing { private get; set; }

}

В каталоге Skydrive Глена Блока, связанном с ответом Мэтью Эббота, я обнаружил нечто простое и легкое: FuncCatalog, Загрузите его здесь: FuncCatalogExtension.

Используя несколько маленьких классов из этого проекта, я теперь мог сделать это:

var funcCatalog = new FuncCatalog();
funcCatalog.AddPart<ISomeThing>(ep => new SomeThing());
var container = new CompositionContainer(funcCatalog);
var batch = new CompositionBatch();
batch.AddExportedObject<ExportProvider>(container);
container.Compose(batch);

var a = container.GetExportedObject<ISomeThing>();
var b = container.GetExportedObject<ISomeThing>();
Другие вопросы по тегам