像简单的 Funq 容器一样用 C# 组合 MEF 部件

发布于 2024-12-03 21:28:58 字数 1194 浏览 1 评论 0原文

Funq 以及可能大多数其他 IoC 容器中,我可以简单地执行此操作来配置类型:

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

How Could I fast Extend 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 中执行此操作?

In Funq and probably most other IoC containers I can simply do this to configure a type:

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

How could I quickly extend MEF (or use existing MEF functionality) to do the same without using attributes.

Here is how I thought I could do it:

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

With this extension method for 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));

}

If I later do:

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

Both instance are the same. How can I force (configure) them to be different instances?

If this is not the way to go, how would I do this in MEF?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(4

浪荡不羁 2024-12-10 21:28:58

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

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

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

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

当然,MEF(Silverlight)确实提供了本机 ExportFactory (和 ExportFactory 类型,支持为每次导入调用创建新实例。您可以通过下载 Glen Block 的 .NET 4.0(桌面)库的 ExportFactory

I would imagine the key is to add the delegate to the container, e.g.:

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

That way you can grab the delegate and execute it:

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

Of course, MEF (Silverlight) does provide a native ExportFactory<T> (and ExportFactory<T,TMetadata> type that supports the creation of new instances for each call to import. You can add support for this by downloading Glen Block's ExportFactory for .NET 4.0 (Desktop) library.

微暖i 2024-12-10 21:28:58

如果你不想使用属性,你可以使用这个技巧(基于标记Seemann 的博文)。

首先,创建一个如下所示的通用类:

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

If you don't want to use attributes, you can use this trick (based on Mark Seemann's blogpost).

First, create a generic class like this:

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

Now you can register any class you want in the container, like this:

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

Alternatively, you could implement your own export provider derived from ExportProvider, which allows you to pretty much duplicate Funq's way of working:

var provider = new FunqyExportProvider();
provider.Register<IFoo>(context => new Foo());
var container = new CompositionContainer(provider);
奢欲 2024-12-10 21:28:58

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

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

}

Both instance are the same. How can I force (configure) them to be different instances?

Simply mark the SomeThing class like this:

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

And then you will get different instances wherever you import ISomeThing.

Alternatively, you can also set a required creation policy on an import:

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

}
烟柳画桥 2024-12-10 21:28:58

在 Glen Block 的 Skydrive 目录中链接到 Matthew Abbott 的回答 我发现了一些看起来简单且轻量级的东西: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>();

In Glen Block's Skydrive directory linked to in Matthew Abbott's answer I found something that seems simple and lightweight: A FuncCatalog. Download it here: FuncCatalogExtension.

Using the few little classes from that project I could now do this:

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>();
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文