Creating multiple instances of Imported MEF parts
Asked Answered
A

6

11

Currently my WPF application imports a part like this

[Import(typeof(ILedPanel)]
public ILedPanel Panel { get; set; }

But this gives ma a single intance of the class that implements ILedPanel. What I really want to do is have the ability to create as many instances that I need. Please note there is only one Export for ILedPanel included with the software at any given time.

(If I use an import with List that gives me one instance for every class implementing ILedPanel)

Any suggestions?

Anacoluthon answered 3/6, 2009 at 23:19 Comment(1)
I'm not sure it's a good way but I simply went with Activator.CreateInstance(Panel.GetType());Anacoluthon
E
8

There isn't "built in" support for this in MEF today, but before reverting to Service Locator, you might find some inspiration here: http://blogs.msdn.com/nblumhardt/archive/2008/12/27/container-managed-application-design-prelude-where-does-the-container-belong.aspx

The essential idea is that you 'import' the container into the component that needs to do dynamic instantiation.

More direct support for this scenario is something we're exploring.

Nick

UPDATE: MEF now has experimental support for this. See this blog post for more information.

English answered 3/6, 2009 at 23:39 Comment(3)
UPDATE: this feature has made its way into MEF "Preview 7" as PartCreator<T> - see the MEF wiki for information (mef.codeplex.com/Wiki/…)English
But only for Silverlight it would seemAnacoluthon
This was added to Preview 8 for non-Silverlight and then pulled from Preview 9! Grrr.Passover
D
11

All of the other answers are pretty old, so they don't mention a relatively new feature in MEF called ExportFactory. This generic class allows you to import ExportFactory<ILedPanel> and create as many instances as you like whenever you need them, so your code would look like this:

[Import(typeof(ILedPanel)]
public ExportFactory<ILedPanel> PanelFactory { get; set; }

public ILedPanel CreateNewLedPanelInstance()
{
    return PanelFactory.CreateExport().Value;
}

This method also satisfies any imports that created part has. You can read more about using the ExportFactory class here.

Diderot answered 20/11, 2013 at 12:37 Comment(1)
That is basically the build in solution for a mechanism I was about to suggest, anybody can build self. You actually create a factory class that has a injectable property. Whenever you call MEF's populate object method, it gets a new instance that it then can return. A build in ExportFactory is certainly nicer.Glyph
D
10

I'm not sure if this is what Nicolas is referring to, but you could import a Factory class rather than an instance class, like this:

[Import(typeof(ILedPanelFactory)]
public ILedPanelFactory PanelFactory { get; set; }

...and then later in your code...

ILedPanel panel = PanelFactory.BuildPanel();
Diabolic answered 4/6, 2009 at 11:6 Comment(0)
E
8

There isn't "built in" support for this in MEF today, but before reverting to Service Locator, you might find some inspiration here: http://blogs.msdn.com/nblumhardt/archive/2008/12/27/container-managed-application-design-prelude-where-does-the-container-belong.aspx

The essential idea is that you 'import' the container into the component that needs to do dynamic instantiation.

More direct support for this scenario is something we're exploring.

Nick

UPDATE: MEF now has experimental support for this. See this blog post for more information.

English answered 3/6, 2009 at 23:39 Comment(3)
UPDATE: this feature has made its way into MEF "Preview 7" as PartCreator<T> - see the MEF wiki for information (mef.codeplex.com/Wiki/…)English
But only for Silverlight it would seemAnacoluthon
This was added to Preview 8 for non-Silverlight and then pulled from Preview 9! Grrr.Passover
H
5

Unless I misunderstand the question, it looks like it would be solved by simply using a CreationPolicy.NonShared.

This assumes that the code declaring the Panel exists everywhere you want a panel. You would get a new instance of ILedPanel in every instance of every class that had this declaration (the import).

Herrod answered 24/7, 2009 at 13:32 Comment(1)
That's true. But there is only one class that implements ILedPanel with any distribution of the software. So that's a single instance... it's not clean of courseAnacoluthon
E
3

Looking at the shapes game sample that comes with MEF, there is the ShapeFactory class:

[Export]
public class ShapeFactory
{
    private readonly Random random = new Random((int)DateTime.Now.Ticks);

    [Import]
    private ICompositionService CompositionService { get; set; }

    public IShape GetRandomShape()
    {
        var shapeRetriever = new ShapeRetriever();

        CompositionService.SatisfyImports(shapeRetriever);

        int randomIndex = random.Next(shapeRetriever.PossibleShapes.Length);

        return shapeRetriever.PossibleShapes[randomIndex].GetExportedObject();
    }

    private class ShapeRetriever
    {
        [ImportMany(RequiredCreationPolicy = CreationPolicy.NonShared)]
        public Export<IShape, IShapeMetadata>[] PossibleShapes { get; set; }
    }
}

Which demonstrates creating a random shape instances "on demand"... I would think in your scenario you could do something similar without the selection of a random implementation, as you suggest there would be only one implementation of ILedPanel registered.

Emmen answered 10/7, 2009 at 2:22 Comment(0)
P
2

i think you mean you want to use MEF in this instance like a service locator rather than a dependency injection container. Try looking at examples for ValueResolver

Placencia answered 3/6, 2009 at 23:24 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.