composing MEF parts in C# like a simple Funq container

冷暖自知 提交于 2019-12-12 03:48:15

问题


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?


回答1:


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.




回答2:


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



回答3:


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

}



回答4:


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


来源:https://stackoverflow.com/questions/7361081/composing-mef-parts-in-c-sharp-like-a-simple-funq-container

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!