Adding an instance in MEF

Jan 7, 2010 at 10:12 PM

Does anyone know how to add an instance to MEF?

In Unity, you are able to create an instance of a type, and add it to the container.

I don't see how I can do this in MEF, and I do understand that MEF wants to do the creation for me.

Jan 7, 2010 at 10:47 PM

There are several ways to do this.

1. You can create a part that has a property export which will add the instance. For example the snipped below will Export the Application class in WPF.

public class ApplicationPart
{
     [Export]
     public Application ApplicationExport {get;set;}
}

2. You can add instances directly to the container by calling the ComposeExportedValue extension method which lives in the System.ComponentModel.Composition namespace. For example.

var container = new CompositionContainer();
container.ComposeExportedValue<Application>(Application.Current);
 

Jan 7, 2010 at 10:59 PM

FANTASTIC!!!

I had tried some code you had shown before, but it had the undesirable effect of calling my implementation of IPartImportsSatisfiedNotification... YIkes(code below).

///////////////////////////////
// Note:  The type must be decorated with the export attribute
var batch = new CompositionBatch();
var part = batch.AddPart(MyType);
App.GetContainer().Compose(batch);
/////////////////////////////////////////////

I LOVE your second implementation because I don't even have to decorate the class.

BTW, MEF is really great.  I love Unity as well, but MEF allows us to integrate all of it's goodness into our existing code in a very unobtrusive way.

Thanks!

Jan 7, 2010 at 11:03 PM

Glad to hear it Dewey!

The second implementation is ideal for integration scenarios because it does not require access to the host to execute it. It also provides the benefits you mentioned in terms of attributes, as does ComposeExportedValue.

 

Jan 11, 2010 at 2:29 PM

Hi.  I had a similar need to add already created objects to a composition container (see my stackoverflow question for details).  I used the CompositionBatch with some success.

One thing I noticed while trying to solve the problem was an asymmetry in how exports can be defined.  The type of the already created objects were only known at runtime instead of compile time, so I could not use AddExportedValue directly.

 

IBaseInterface foo = ...
//foo implements IDerivedInterface

batch.AddExportedValue(typeof(IDerivedInterface).FullName, foo);

//a part needing to use an IDerivedInterface might look like this:

class SomeObj
{
    [ImportingConstructor]
    public SomeObj(IDerivedInterface derivedFoo) {}
}

This failed to compose because the exported value I added was inferred to be a base type.  I also tried to add an export by creating a primitive Export but it's constructors did not allow me to specify the type.
This is asymmetric because when you declare an Export attribute, you can specify the type.  I guess I was looking for and surprised not to find the AddExportedValue(Type exportType, object obj) function.
The solution I found I was not too happy with.  I found that if I created an Export and set the metadata property "CompositionConstants.ExportTypeIdentityMetadataName" equal to the type identity I could add the export and have it compose correctly.  Perhaps another extension method somewhere would be nice.
TTFN
Dave

 

 

Developer
Jan 11, 2010 at 4:00 PM

Dave - Did you try batch.AddExportedValue<IDerivedInterface>(foo)? I think that will do what you want.

Jan 11, 2010 at 7:32 PM

That does work, but the problem is really that I don't have the derived types until runtime.  There is a dictionary of <Type, IBaseInterface> that is populated by a non-MEF part of the system and I want to make those types available to MEF composition.  What I really wanted to use was:

 

foreach(var entry in registeredStuff)
{
    batch.AddExportedValue(entry.Key, entry.Value);
}

 

 

or something similar.  I know I can use reflection to create and call the right generic method at runtime, but what struck me was how the attributed model allowed specifying types in parameter lists, but the more manual methods did not.

e.g. I can do this:

 

[Export(typeof(IDerivedFoo))]
class Foo :...

But not this:

 

var export = new Export(typeof(IDerivedFoo), () => existingFoo);

 

 

 

 

 

Aug 20, 2010 at 9:23 PM

wow !!  that is the single best tidbit of info i've found on MEF so far, it look how deep its buried !!  to reiterate:

var container = new CompositionContainer();
container.ComposeExportedValue<Application>(Application.Current);

in response to dreich, i believe that the Export attribute is doing a type.GetType().ToString() to create a string contract name for the Export.  you should be able to do the same thing.  the new Export has an overload for string contract.

Aug 20, 2010 at 10:47 PM
Edited Aug 20, 2010 at 10:50 PM

We do create a contract name based on the type name however it's not exactly the same. If the type is generic for example we represent it different, for non generic types though it is essentially the type name.

Glenn

Aug 22, 2010 at 11:01 AM
Edited Aug 22, 2010 at 11:07 AM

A contract name is derived from the type name but it is not simply Type.FullName. There's a class which has a lot of extension methods that you might wanna take a closer look at, System.ComponentModel.Composition.AttributedModelServices.

It has a method GetContractName(Type) which will return the contract name as MEF expects it to. There's also something called TypeIdentity which judging by the implementation right now looks exactly the same as the contract name, in fact, GetContractName(Type) just redirects the call to GetTypeIdentity(Type).

If you take a look at this class in .NET reflector or browse the source code you'll also see how these extension methods discussed here leverages the CompositionContainer.Compose(CompositionBatch) method to add instances in the container. It might shed some light on the inner workings, I found this particularly helpful at one point.