【问题标题】:composing MEF parts in C# like a simple Funq container像一个简单的 Funq 容器一样在 C# 中组合 MEF 部件
【发布时间】:2011-09-09 11:40:12
【问题描述】:

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 中做到这一点?

【问题讨论】:

    标签: ioc-container mef func


    【解决方案1】:

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

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

    这样你就可以获取委托并执行它:

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

    当然,MEF (Silverlight) 确实提供了原生 ExportFactory&lt;T&gt;(和 ExportFactory&lt;T,TMetadata&gt; 类型,支持为每次导入调用创建新实例。您可以通过下载 Glen Block 的 ExportFactory for .NET 4.0 (Desktop) library 添加对此的支持。

    【讨论】:

    • 你有一个关于如何在我的场景中使用 ExportFactory 的示例(显式配置而不是属性)?
    • 嗯,在你链接的那个 Skydrive 文件夹中,我发现了一些看起来比 ExportFactory 更简单和轻量级的东西:FuncCatalog:skydrive.live.com/self.aspx/blog/…
    【解决方案2】:

    如果不想使用属性,可以使用这个技巧(基于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);
    

    【讨论】:

    • +1 这是个好技巧!但是现在我想起来了,一个不错的功能也是funcCatalog.AddPart&lt;ISomeThing&gt;( exportPovider =&gt; new SomeThing(ep.GetExportedObject&lt;ISomeThingElse&gt;())); 这是从我的回答中从 FuncCatalog 中偷来的。用你的方法解决额外的依赖是不可能的,对吧?
    • @bitbonk:Mark Seemann 的原始帖子(我链接到)展示了如何调整这个技巧来解决额外的依赖关系。
    【解决方案3】:

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

    只需像这样标记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; }
    
    }
    

    【讨论】:

    • 我的问题背后的想法是使用属性进行配置。
    • 我很怀疑,但从您的问题中并不清楚您是否知道这样做的“正常 MEF 方式”。我将发布另一个答案来处理您避免属性的要求。
    【解决方案4】:

    在与Matthew Abbott's answer 链接的 Glen Block 的 Skydrive 目录中,我发现了一些看似简单且轻量级的东西:A 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>();
    

    【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-01-10
    • 2023-03-21
    • 1970-01-01
    • 2010-09-07
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多