用C#编写MEF部分就像一个简单的Funq容器

时间:2011-09-09 11:40:12

标签: ioc-container mef func

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 个答案:

答案 0 :(得分:1)

我认为关键是将委托添加到容器中,例如:

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 for .NET 4.0 (Desktop) library

答案 1 :(得分:1)

如果您不想使用属性,可以使用此技巧(基于Mark Seemann's blogpost)。

首先,创建一个这样的泛型类:

[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);

答案 2 :(得分:0)

  

两个实例都是一样的。如何强制(配置)它们为不同的实例?

只需将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; }

}

答案 3 :(得分:0)

在Glen Block的链接到Matthew Abbott's answer的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>();