I want New instance every time

May 23, 2009 at 12:02 PM
Edited May 23, 2009 at 12:03 PM

In the previous version of MEF, If we mark the export as [CompositionOptions(CreationPolicy = CreationPolicy.Factory)], we use to get new instance every time.  How do i do the same in MEF 5 ? <font size="2">

In MEF 5 ,

PartCreationPolicyAttribute(CreationPolicy.NonShared)] returns me the same instance every time, but i want new instance every time.

 

 

Thanks,

Bhupesh.

May 23, 2009 at 6:41 PM
Edited May 23, 2009 at 8:43 PM

That is the correct syntax, and it should be returning an instance every time.

How are you importing the export that has PartCreationPolicy attribute on it? If you are importing an Export<Foo> and then calling GetExportedObject then it will return the same Foo instance every time, though in the past it would return different instances. If you want to get a different instance each time, then you need a different Export instance. You can get this by creating a helper class such as ExportInstanceProvider below that you import.

 

var container = new Container(catalog);

container.ComposeExports(new ExportInstanceProvider(container);

 

[Export]

public class ExportInstanceProvider {

  private CompositionContainer _container;

  public ExportInstanceProvider(CompositionContainer container) {

    _container = container;

  }

  public Export<T> GetExport<T>() {

    return _container.GetExport<T>();

  }

  public Export<T> GetExport<string>(string contract) {

    return _container.GetExport<T>(contract);

  }

}

May 23, 2009 at 8:03 PM

Can you please provide me some more sample code or links for singleton/Multiple in latest MEF ?

This is how I was doing initially, and I got new instance every time but not getting it now. Added [PartCreationPolicyAttribute(CreationPolicy.NonShared)] attribute also to the export.

[Import]

public ExportCollection<IViewOfAddInContractBase> Calculators { get; set; }

 

var catalog = new AggregateCatalog();

catalog.Catalogs.Add(new DirectoryCatalog(@"AddIns"));

container = new CompositionContainer(catalog);

CompositionBatch batch = new CompositionBatch();

batch.AddPart(this);

container.Compose(batch);

foreach (Export<IViewOfAddInContractBase> export in Calculators)

{

export.GetExportedObject();

export.GetExportedObject();

}

May 23, 2009 at 8:52 PM
Edited May 23, 2009 at 10:04 PM

Hi Bhupesh, I see what you are trying to do, and yes, this used to work, however we heard from customers the behavior was problematic and inconsistent with usage. In MEF today, a single Export always returns the same instance when GetExportedObject is called. You can still achieve what you were trying to do, but the approach is a bit different.  You can do it with the class I sent, by adding two more methods (see below). I've also changed the class now to be generic thus expressing more intent on its usage within the code.

Take the following code and copy it into a new console app. Add a reference to System.ComponentModel.Composition, compile and execute.

 using System;

using System.Collections.Generic;

using System.ComponentModel.Composition;

using System.ComponentModel.Composition.Hosting;

 namespace ExportInstanceProviderSample

{

    class Program

    {

        static void Main(string[] args)

        {

            var catalog = new TypeCatalog(typeof(Calculator1), typeof(Calculator2), typeof(Part));

            var container = new CompositionContainer(catalog);

            container.ComposeExportedObject(new ExportInstanceProvider<IViewOfAddinContractBase>(container));

            var part = container.GetExportedObject<Part>();

            Console.ReadLine();

        }

    }

 

    [Export]

    public class Part

    {

        private ExportInstanceProvider<IViewOfAddinContractBase> _provider;

         [ImportingConstructor]

        public Part(ExportInstanceProvider<IViewOfAddinContractBase> provider)

        {

            _provider = provider;

 

            for (int i = 0; i < 2; i++)

            {

                CreateCalculators();

            }

        }

 

        private void CreateCalculators()

        {

            foreach (var export in _provider.GetExports())

            {

                var calculator = export.GetExportedObject();

                Console.WriteLine(calculator.GetHashCode());

                //do something

            }

        }

    }

 

    public interface IViewOfAddinContractBase { }

 

    [PartCreationPolicy(CreationPolicy.NonShared)]

    [Export(typeof(IViewOfAddinContractBase))]

    public class Calculator1 : IViewOfAddinContractBase

    {

    }

 

    [PartCreationPolicy(CreationPolicy.NonShared)]

    [Export(typeof(IViewOfAddinContractBase))]

    public class Calculator2 : IViewOfAddinContractBase

    {

    }

 

    [Export]

    public class ExportInstanceProvider<T>

    {

        private ExportProvider _provider;

         public ExportInstanceProvider(ExportProvider provider)

        {

            _provider = provider;

        }

 

        public Export<T> GetExport()

        {

            return _provider.GetExport<T>();

        }

 

        public Export<T> GetExport(string contract)

        {

            return _provider.GetExport<T>(contract);

        }

 

        public IEnumerable<Export<T>> GetExports()

        {

            return _provider.GetExports<T>();

        }

        public IEnumerable<Export<T>> GetExports(string contract)

        {

            return _provider.GetExports<T>(contract);

        }

    }

}

When you run it, you will see that there are 4 calculator instances (2 sets of each calculator) which are created.

From: Bhupesh [mailto:notifications@codeplex.com]
Sent: Saturday, May 23, 2009 12:03 PM
To: Glenn Block
Subject: Re: I want New instance every time [MEF:57264]

 

From: Bhupesh

Can you please provide me some more sample code or links for singleton/Multiple in latest MEF ?

This is how I was doing initially, and I got new instance every time but not getting it now. Added [PartCreationPolicyAttribute(CreationPolicy.NonShared)] attribute also to the export.

[Import]

public ExportCollection<IViewOfAddInContractBase> Calculators { get; set; }

 

var catalog = new AggregateCatalog();

catalog.Catalogs.Add(new DirectoryCatalog(@"AddIns"));

container = new CompositionContainer(catalog);

CompositionBatch batch = new CompositionBatch();

batch.AddPart(this);

container.Compose(batch);

foreach (Export<IViewOfAddInContractBase> export in Calculators)

{

export.GetExportedObject();

export.GetExportedObject();

}

Read the full discussion online.

To add a post to this discussion, reply to this email (MEF@discussions.codeplex.com)

To start a new discussion for this project, email MEF@discussions.codeplex.com

You are receiving this email because you subscribed to this discussion on CodePlex. You can unsubscribe or change your settings on codePlex.com.

Please note: Images and attachments will be removed from emails. Any posts to this discussion will also be available online at codeplex.com

May 24, 2009 at 2:16 PM

Hi Glenn, a MEF user has to deal with this scenario (NonShared) too often that everyone needs to create himself a helper class like your ExportInstanceProvider class.

I register the container itself and then retrieve it to create the non-shared objects.

1. Register the container object

container = new CompositionContainer(catalog);
CompositionBatch batch = new CompositionBatch();
batch.AddExportedObject(container);
container.Compose(batch);


2. In the class that needs to use the container you can inject it

[ImportingConstructor]
public ApplicationController(CompositionContainer container, IShellView shellView)
{
 

3. Create the NonShared IOptionsView object

private void ShowOptionsView()
{
    IOptionsView optionsView = container.GetExportedObject<IOptionsView>();
    optionsView.ShowDialog();
}


I’m worrying that the NonShared scenario isn’t supported as well as the Shared one. In my applications both scenarios Shared and NonShared comes around same frequently.

I might suggest that you invest some time to improve the API usability for the NonShared scenario.

thx,
  jbe

May 24, 2009 at 8:13 PM
Edited May 24, 2009 at 8:14 PM

Hi JBE

We support non-shared imports on parts in the same way that we support shared parts. For example if the caclulator collection was being imported, then each part that imported it would get a new set of calculators if they are marked as  non-shared.

In this case the scenario Bhupesh is is describing (and which you show in your sample) is for dynamically creating non-shared parts on-the-fly.  For this scenario, I agree we need better support. We are looking into supporting a Factory<T> in the future that would allow you to import a Factory<IOptionsView> when you need to dynamically generate new export instances on the fly, such as in the scenario you described.

For the time being though you need to add the container to itself, or add it as an export provider (EP only supports retrieval type functionality). The helper class is just a wrapper on this and is not really necessary, but helpful. The advantage of it, is it expresses clearly in the part's dependencies the intent, that is the kinds of things it is going to be resolving i.e. IOptionsView, ICalculator, etc) as opposed to an open-ended contract, in which case you have to read through the code to understand how it is being used.

Thanks for the feedback

Glenn

May 24, 2009 at 9:29 PM

I do a container.GetExports<T>every time a i need a new instance, then  traverse through the export metadata, and call GetExportedObject on the export i need. It is creating a new instance for me every time.

Is this approach also fine ? Any draw backs with this approach ?

May 24, 2009 at 9:36 PM

Yes, it is basically the same approach.

Glenn

May 25, 2009 at 6:53 PM

Hi Glenn, thanks for the prompt response. I can see your point of the Export Providers advantage.
 
I really like the idea with the Factory<T> class and I’m looking forward to see it in a future MEF release.
 
 
jbe

Aug 5, 2009 at 5:58 PM

There is no ComposeExportedObject in CompositionContainer in MEF preview 6 and I cannot find a sample of how to do that with a CompositionBatch. Can anybody help me?

Aug 5, 2009 at 6:09 PM
siderevs wrote:

There is no ComposeExportedObject in CompositionContainer in MEF preview 6 and I cannot find a sample of how to do that with a CompositionBatch. Can anybody help me?

 

What you're looking for is CompositionContainer.ComposeExportedValue (an extension method.)

Cheers,

Nick

Aug 5, 2009 at 6:59 PM

Thank you Nick, It works.

Jun 15, 2010 at 5:25 PM
Is there an update on how to do this in the latest version of MEF (Preview 9)? It appears that the Export GetExport<T>() no longer exists and has been replaced with IEnumerable<Export> GetExports( ImportDefinition ), which I'm having a hard time understanding how to use (been searching all morning). My co-worker suggested what I should really be doing here is instantiating singleton factories that then create instance objects as I see fit, effectively circumventing MEF when non-shared data is required. If I can't figure this out, I suppose that is the way I will do it, but it feels like I'm leaving on the table something that MEF should be able to handle easily. To clearly restate my intent: I want to be able to use the PartCreationPolicy.Any on the export side, and then determine when to use the shared versus non-shared instance on the import side. I can get unique instances if I set the PartCreationPolicy to NonShared on the Export side, but then I am always reading in new data (which might be what I want), but it spurred the question of how to decide on the Import side the creation policy when it was set to Any on the Export side. (is that clear? Feels rambling...ugh...)
Nov 1, 2010 at 12:19 PM

Since I have multi threaded application, I need to get new instance of composed part every time.

I have one class called ClassA Which is being composed in RegisterComponents class as under:

 

public class ClassA : IClassA
{
    // Some logic goes here...
}

[Export]
public class RegisterComponents
{
   [ImportingConstructor]
   public VitalsModule(CompositionContainer container)
      {
            this.container = container;
      }

   public void RegisterServices()
     {
       this.Container.ComposeExportedValue<IClassA>(new ClassA());

}


Now I am getting instance of ClassA into another class ClassB which is being called by multiple threads. I want new instance of 
ClassA every time I get it from CompositionContainer.

public void ClassB
{
// this way i m getting lazy export
var lazyInstance = CompositionContainerHost.CompositionContainer.GetExport<IClassA>();

// Now i m creating instance of this export
// Here i need new instance every time...
// HERE I M NOT GETTING NEW INSTANCE EVERY TIME AND CLASSA CTOR WILL NOT GET CALLED EVERYTIME.

var instance = lazyInstance.Value;

}

Thanks in Advance.

 

 

Nov 1, 2010 at 8:48 PM

You can use ExportFactory<T> to get this behavior.

Nov 2, 2010 at 5:22 AM

Can you please explain me how ExportFactory<T> would help me?

I am using ExportFactoryProvider and assign my Container to it.

var exportFactoryProvider = new ExportFactoryProvider();

             this.container = new CompositionContainer(this.catalog, true,exportFactoryProvider);
                exportFactoryProvider.SourceProvider = this.container;
                CompositionHost.Initialize(this.container);
I also set isThreadSafe property to "true" for multi threading environment but still my thread content is getting overwritten 
and I am not getting new instance every time.
Can I add attribute "PartCreationPolicy" on ClassA (considering my prev. post) without declaring it as an export. like this
[PartCreationPolicy(CreationPolicy.NonShared)]
public class ClassA
{
}
I did this but still this will not return me new instance of ClassA from Container.