Getting the right type exported from the container...

Jun 19, 2010 at 6:26 AM

Hi, I've got a problem that I haven't been able to solve correctly, yet.  First, some background...

I have a simple interface, let's call it MyInterface, and I have two classes, each in separate assemblies, called Concrete1 and Concrete2, and both inherit and export MyInterface.  For example:

public interface MyInterface
  string GetName();

public class Concrete1 : MyInterface
  string GetName() { return "concrete1"; }

public class Concrete2 : MyInterface
  string GetName() { return "concrete2"; }

The application has an [ImportMany(typeof(MyInterface)] so I can load multiple plugins.  At some point, I will look at a file that maps plugin names (those that get returned by GetName()) to a friendly name that appears in the GUI.  For example, it could look like this:

concrete1 : "one concrete1 object"
concrete1 : "another concrete1 object"
concrete2 : "the only concrete2 object"

When I see the value before the colon, I take that and then loop over the IEnumerable<MyInterface> and compare its GetName() value to that of the value before the colon.  This is how I know which type of MyInterface object I want to create -- either Concrete1 or Concrete2.

OK, so here's the problem -- how do I actually instantiate the right object through MEF?  Here's what I have tried:

Attempt #1: Use GetExportedValue<T>

This approach seemed to work at first when I only tested it with Concrete1.dll.  Everytime I saw a "concrete1" in the file, I was able to create a new instance of that plugin.  But when I added Concrete2.dll, GetExportedValue<> bombed because there were more exports than expected.  I assume this fails because the result would be ambiguous, since I was asking the MEF container to give me a MyInterface object of some kind, and didn't ask for a Concrete1 or Concrete2 object.  I assume MEF wouldn't allow this since the exported type was MyInterface anyway!

Attempt #2: Use Activator.CreateInstance<T>

Totally works, except on plugins that rely on MEF to import things.  If you don't create the object with MEF, you will end up with null for everything that you attempt to [Import].  Bummer!

So if I have an IEnumerable<MyInterface>, and I can call GetType() on each element as I iterate over that collection, how can I use that information to politely ask MEF to please, please, please create me an object of that type?

Jun 21, 2010 at 2:04 PM
Here's how I ended up solving the problem -- not sure if it's the best way. I went over the docs again for CompositionContainer, and found GetExportedValues<T>. So I just looped over the IEnumerable<T> that gets returned, and when the type matches, I save the reference to the object created by the container.