Factory Composition Behaviour

Nov 29, 2008 at 5:10 AM
Edited Nov 29, 2008 at 5:10 AM
Hi guys,

I've been been using MEF a little lately and reading through the sample code an I'm a little confused about the behaviour of parts marked with:

[CompositionOptions(CreationPolicy = CreationPolicy.Factory)]

I was expecting that by doing this each call to GetExportedObject would create a new instance of the class. After playing around with this and looking at the Mefris code I can see that this doesn't appear to happen and that a new part containing the export has to be composed in order to create a new instance each time (see the ShapeFactory.GetRandomShape() method and ShapeRetriever class).

Am I just being dumb here? If so could you help me out with a little explaination as to why this is the behaviour?

Thanks,
Dave

Dec 1, 2008 at 5:41 PM
Hi Dave,

Not a MEF guru, but I also played a bit with MefTris sample and MEF Preview3 code...
My conclusions are the same as yours:
  • CreationPolicy.Singleton: (default) keeps a single instance of your export across multiple parts.
  • CreationPolicy.Factory: each part contains its own instance of your export.
So at least if you're dumb, I'm even dumber (as I'm confirming) !


As you, I wanted to mark types with this flag so that a new instance would have been created each time GetExportedObject was called.
Too bad, the Export class itself contains the reference to the instance created, and I did not find how to override this behaviour without hacking/duplicating a consequent part of MEF basecode.
I even tried (unsuccessfully) to create an Adapter to translate my types into a factory method...

So if anyone knows how/if such a Factory behaviour is possible (I mean just by marking exported "factored" types, without Factory method or classes), please feel free to drop a note here in addition to the explanations requested by Dave (and me).

Thanks,
Julien

Dec 1, 2008 at 6:05 PM

Singleton and Factory apply to the part, not the exports. So Singleton means that there is a single part instance in the container for all pulls on any of its exports. Factory means that every export pull forces creation of a new part.

The caveat is that having a Singleton doesn’t actually enforce that the exports are singleton, nor does factory ensure the export is a non-singleton J For example you could have a part that is a singleton, but which contains a property export whose code is “return new Foo()”. You could also have a part that is a factory, but which contains a property export whose code is “return _myStaticFoo;”

If the export is at the part (class level) then it will behave as you expect as the part and export are synonymous in that case.


Does this make sense, or does it utterly confuse you?

Glenn

From: jweber [mailto:notifications@codeplex.com]
Sent: Monday, December 01, 2008 10:41 AM
To: Glenn Block
Subject: Re: Factory Composition Behaviour [MEF:41068]

From: jweber

Hi Dave,

Not a MEF guru, but I also played a bit with MefTris sample and MEF Preview3 code...
My conclusions are the same as yours:

  • CreationPolicy.Singleton: (default) keeps a single instance of your export across multiple parts.
  • CreationPolicy.Factory: each part contains its own instance of your export.

So at least if you're dumb, I'm even dumber (as I'm confirming) !


As you, I wanted to mark types with this flag so that a new instance would have been created each time GetExportedObject was called.
Too bad, the Export class itself contains the reference to the instance created, and I did not find how to override this behaviour without hacking/duplicating a consequent part of MEF basecode.
I even tried (unsuccessfully) to create an Adapter to translate my types into a factory method...

So if anyone knows how/if such a Factory behaviour is possible (I mean just by marking exported "factored" types, without Factory method or classes), please feel free to drop a note here in addition to the explanations requested by Dave (and me).

Thanks,
Julien

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

Dec 1, 2008 at 9:51 PM
Hi Glenn, thanks for the quick response!

If I understand you correctly you're saying that the behaviour we expect is the correct behaviour, but there is always the potential for the exported parts to not 'support' this, right?

Perhaps I don't fully understand the difference between a 'part' and an 'export' (actually, I can tell you now that I don't fully fully understand the difference :-) ). When you say that the creation policy refers to the part does that mean the class/type that an export 'wraps'?

Lets say I have multiple classes implementing the IPlugin interface and they are all marked with [Export(typeof(IPlugin))] and also [CompositionOptions(CreationPolicy = CreationPolicy.Factory)] (it's my understanding that these classes are referred to as Parts?). I then create the hosting application and add a property of type ExportCollection<IPlugin> and mark it with [Import]. When I iterate through each Export<IPlugin> (the Export, not the Part?) I want GetExportedObject() to return a new instance of the class each time.

Now that's obviously what I expect/want to happen. In actual fact the GetExportedObject() returns the same instance every time. Given that I have three questions really:

1) Is what I am trying to do a valid use for MEF? It feels like it is, as what I am doing is very similar to the Mefris sample. Having said that the Mefris code doesn't 'feel' right in places (especially ShapeFactory).
2) If so, what is the best way to get the behaviour I'm after? I've implemented the same mechanism as the Mefris sample but it feels like a real hack to me :-/ It's also ridiculously slow (my equivalent ShapeRetriever is created potentially thousands of times) further leading me to believe I'm doing something that I shouldn't be doing.
3) What is the factory composition used for, if not to specify that a part should be created each time the export tries to get the object? It may be that I'm going about this the wrong way and I simply need to understand more about factory behaviour within MEF.

Thanks,
Scriv

P.S. Yeah, this is pretty much the same question I know but I thought I'd try to re-phrase so that you understand what I'm trying to do rather than me simply crying out 'It's not working for me!' :)

Dec 2, 2008 at 4:24 PM
Hi Glenn,

First of all, I apologize for this long post... You surely have more interesting things to do than help newbies understand how MEF works and how to distort it :)
So thank you for your help and what you do for the community.
Dave, as it seems we're looking for the same thing, I hope you don't mind I squat your thread.


(To be consistent with Dave's syntax, I'll keep the IPlugin example.)

davescriven: "When I iterate through each Export<IPlugin> ... I want GetExportedObject() to return a new instance of the class each time."
Well, personally I'm searching how to:
  • Quickly create a new instance from an item of an Imported ExportCollection<> (without recreating a new [Import] of the collection as in the MefTris.ShapeFactory sample)
  • Simplify development of such IPlugin implementation (the less code, the better)
As Dave, I'd enjoy a way to tell the Export instance that the GetExportedObject method should return a new instance of the class, but this is not a mandatory feature: some "magic method" could also do the trick. I mean, in the client code (ie. handling the collection), you obviously know that the items in this very ExportCollection will have this behaviour, don't you ?

So, in my opinion, the ultimate solution would be something like:

// --- Core assembly
public interface IPlugin {...}

[Import]
ExportCollection<someType> availableExports {get; private set;}

/// <summary>
/// Creates a new instance of IPlugin each time.
/// </summary>
IPlugin CreateNewPluginInstance(someParameters)
{
  foreach(var export in availableExports)
  {
    if(someCondition) // For example a condition on the Metadata of the export.
    {
      // IPlugin instance = export.GetExportedObject(); // Does not work actually, but... who knows ? :)
      IPlugin instance = DoSomeMagic(export); // Is the magic done in MEF, or by a MEF adapter, client code... ?
      return instance;
    }
  }
  return null;
}

// --- MyPlugin assembly (references Core assembly)
[SomeDecorations] // This is the important part: I'd like to only have attributes on the type created by the magic.
public class MyPlugin : IPlugin {...}


However, I failed to reach this level, and don't know if this is possible.
I ended up with two working options that do not fully satisfy me...



// ***********************************************
// Option #1
// Export a Factory class. Bloats the projects with twice as much classes...

// --- Core assembly
interface IPlugin { ... }

interface IFactory<T> // Generic parameterless factory
{
  T CreateInstance();
}

[Import]
ExportCollection<IFactory<IPlugin>> availablePluginFactories {get; private set;}

IPlugin CreateNewPluginInstance(someParameters)
{
  foreach(var export in availablePluginFactories)
  {
    if(someCondition) // For example a condition on the Metadata of the export.

      return export.GetExportedObject().CreateInstance();
  }
  return null;
}


// --- MyPlugin assembly (references Core assembly)
class MyPlugin:IPlugin { ... } // No attributes.

[Export(IFactory<IPlugin>)]
public class MyPluginFactory : IFactory<IPlugin>
{
  public IPlugin CreateInstance() { return new MyPlugin(); }
}





// ***********************************************
// Option #2
// Export a (preferably static) factory method.
//    Does not allow a concrete MyPlugin to implement multiple IPlugin (IPlugin1, IPlugin2, ...) interfaces.

// --- Core assembly
interface IPlugin { ... }

[Import("PluginBuilder")]
ExportCollection<Func<IPlugin>> availablePluginBuilders {get; private set;}


IPlugin CreateNewPluginInstance(someParameters)
{
  foreach(var export in availablePluginBuilders)
  {
    if(someCondition) // For example a condition on the Metadata of the export.

      return export.GetExportedObject()();
  }
  return null;
}


// --- MyPlugin assembly (references Core assembly)
public class MyPlugin : IPlugin
{
  ...

  [Export("PluginBuilder")]
  public static IPlugin CreateInstance() { return new MyPlugin(); }
}




1/ Do you see a better way to achieve the magic that Dave and I are seeking ?
2/ If not, which one do you think is more elegant ? I tend to think #2 is better than #1 (less classes, less code). Do you agree with that ?
3/ What about a converter ? Is there a way to convert a MEF Export (that keeps track of the instance it created) to an Export subclass that creates a new instance each time GetExportedObject is called ? (I coded that but get stucked at runtime: the Imported ExportCollection<IPlugin> is filled with instances of class StructuredValueExport<IPlugin, TMetadataType>, and this class also prevents multiple instances of the exported object from being created... Well, congratulations, that's a rock-solid implementation !)

Of course (well is this really that obvious ?) I don't know the whole MEF thing... Maybe considering an Export<T> as a factory of T is not a good idea.


Thanks again for your help,
Julien

Developer
Dec 2, 2008 at 10:38 PM

Julien - I think you hit nail on the head with "Maybe considering an Export<T> as a factory of T is not a good idea."

Think of Export<T> as a LazyInit object with Metadata. When GetExportedObject is called the first time it initializes the object and then caches it for each additional call.

CreationPolicy.Singleton/Factory have caused a number of misconceptions about what they truly mean which is why we are planning to change the names to CreationPolicy.Shared/NonShared (respectively). This CreationPolicy is applied at the part/type level (as Glen mentioned) and not at an Export level (sometimes one and the same but not always, consider if you are exporting a Property or Field).

  • CreationPolicy.Singleton/Shared: The default CreationPolicy and means that a only one instance of the given part/type will be constructed by the Container and shared by all requestors (via Container.GetExports or the [Import] attribute).
  • CreationPolicy.Factory/NonShared: This means that for every requestor a new instance of the given part/type will be constructed by the Container.

Julien more to your direct question... I think #2 works OK but it does have issues if your MyPlugin has Imports that need to be satisfied by the container as well. You would then need to import dependencies directly in the your class (and they can't be static imports because they aren't support) or you would need to import ICompositionService to satisfy the imports on your MyPlugin.

The ShapeFactory in the Meftris example is really the best I could come up with at the time (Yes I’m to blame for the ShapeFactory ?) that didn’t require me to create and individual factory for every hhape type. Now that we have ExportProvider there is another potential solution for the ShapeFactory:

public class ShapeFactory
...
[Import]
private ExportProvider ExportProvider { get; set; }

public IShape GetRandomShape()
{
    var shapeExports = ExportProvider.GetExports<IShape, IShapeMetadata>();
    int randomIndex = random.Next(shapeExports.Count);
    return shapeExports[randomIndex].GetExportedObject();
}

While this approach technically gets the job done it has a number of issues:

1) It requires you to know that a all implementations of the contract have a CreationPolicy of Factory/NonShared, since this isn’t part of the contract you can ever guarantee this. So if someone implements the contract with a Singleton/Shared part you will basically get that Shared instance and not a new one so there is no way to guarantee you are always getting a new instance.

2) It requires you to have access to an ExportProvider, which means you need to be the host or your host has to know about this dependency and add the Container to itself as an ExportProvider so someone can import it as an ExportProvider (which is what the Meftris host would have to do for that code above).

For these reasons it is recommended that if you want explicit factory behavior than you should actually implement the factory pattern yourself.

Key take away: Today MEF doesn’t really do anything to help make implementing a factory pattern better and that is not really its purpose.

Hope that helps,
Wes

Dec 3, 2008 at 12:55 PM
Wes,

Ok, that's pretty clear, and it helps a lot.

I kinda like the style of this new ShapeFactory : after a second thought, in my case, some imported parts may have a CreationPolicy of Shared; after all, it is the responsability of the [Export]er to declare the policy suited to the part. At least I have to ensure the client code functions properly no matter what the CreationPolicy is.

The only thing I need (or at least I think I need it) is to get the CreationPolicy of an Export at runtime, so I'm able to display on the GUI that "modifying this item may affect some other items".
  1. Do you think I should not need/use this kind of info ? (Maybe it breaks MEF-best-practices, or is illogical, or even stupid...)
  2. Do you think I can rely on the corresponding item in the Export instance Metadata ? Its key ("System.ComponentModel.Composition.IsFactory") is defined in public class StandardKeys, nested in internal class MetadataServices, so is not publicly accessible. Isn't it possible to make it publicly available ? In my code, I'd rather use a shortcut like SomeMefClass.IsFactoryKey than the explicit definition  typeof(ExportDefinition).Namespace + ".IsFactory" (this definition may differ in a future version of MEF).
  3. Is there another way to get the CreationPolicy (without reflecting myself the attributes of anexport.GetExportedObject().GetType()...) ?

Thanks.
Julien
Developer
Dec 5, 2008 at 12:57 AM
To answer your questions directly:
1) If you can accomplish your task without knowing this information then I would definitely shy away from trying to find it out and using it.
2) You should definitely not rely on this internal key because it is may or may not exist when we RTM, we are considering either removing it all together or potentially exposing it publicly, not sure yet what the we may end up with here.
3) Currently no and I certainly wouldn't recommend you doing reflection on the type to find it, that is really making a lot of assumptions and will be very fragile.

We are trying to collect some legitimate scenarios around the idea of the importer knowing the CreationPolicy, so I'm curious what scenarios you see where you would use this information?

Wes