3

Based on the answer for this question What's the difference between CompositionBatch and catalogs? which states that the use of composition batch is useful in situations where objects are built by some other component. This made me think, what real life example does it apply to? Then I started thinking about objects that get built that you aren't in control of. How would you add those instances to the container if you can't add parts that aren't marked as an Export? The only thing that comes to mind is to setup a class with a member of the desired type and marking it as an export.

Is it possible to add instances to a container if they aren't marked as an export?

Community
  • 1
  • 1
ILovePaperTowels
  • 1,445
  • 2
  • 17
  • 30

2 Answers2

6

I'm going to assume that you meant "classes not marked as an export" instead of "instances".

For .NET4.5 and up you can use MEF's convention model.

For .NET4, Mark Seemann has blogged about how you can make clever use of generics and property exports to export existing types. You can create a class like this:

public class MefAdapter<T> where T : new()
{
    private readonly T export;

    public MefAdapter()
    {
        this.export = new T();
    }

    [Export]
    public virtual T Export
    {
        get { return this.export; }
    }
}

And then you can construct a type catalog to export existing types which are not MEF-aware like this:

var catalog = new TypeCatalog(
    typeof(MefAdapter<Foo>),
    typeof(MefAdapter<Bar>), 
    ...);

You could modify this example to add support for types with constructor arguments, exporting interfaces instead of just the class type, etcetera.

Wim Coenen
  • 66,094
  • 13
  • 157
  • 251
2

You need to create your own catalog. It is not an easy task but Here is an example (I haven't used it myself. I could solve my similar problem with InheritedExport)

I repeat the code here if the link dies.

public class ConventionalCatalog : ComposablePartCatalog {
    private List<ComposablePartDefinition> _parts = new List<ComposablePartDefinition>();
    public void RegisterType<TImplementation, TContract>() {
        var part = ReflectionModelServices.CreatePartDefinition(new Lazy<Type>(() => typeof(TImplementation)),
                   false,
                   new Lazy<IEnumerable<ImportDefinition>>(() => GetImportDefinitions(typeof(TImplementation))),
                   new Lazy<IEnumerable<ExportDefinition>>(() => GetExportDefinitions(typeof(TImplementation), typeof(TContract))),
                   new Lazy<IDictionary<string, object>>(() => new Dictionary<string, object>()),
                   null);
                   _parts.Add(part);
    }

    private ImportDefinition[] GetImportDefinitions(Type implementationType) {
        var constructors = implementationType.GetConstructors()[0];
        var imports = new List<ImportDefinition>();

        foreach (var param in constructors.GetParameters()) {
            imports.Add(ReflectionModelServices.CreateImportDefinition(
                new Lazy<ParameterInfo>(() => param),
                AttributedModelServices.GetContractName(param.ParameterType),
                AttributedModelServices.GetTypeIdentity(param.ParameterType),
                Enumerable.Empty<KeyValuePair<string,Type>>(),
                ImportCardinality.ExactlyOne,
                CreationPolicy.Any,
                null));
        }
        return imports.ToArray();
    }

    private ExportDefinition[] GetExportDefinitions(Type implementationType, Type contractType) {
        var lazyMember = new LazyMemberInfo(implementationType);
        var contracName = AttributedModelServices.GetContractName(contractType);
        var metadata = new Lazy<IDictionary<string, object>>(() => {
                           var md = new Dictionary<string, object>();
                           md.Add(CompositionConstants.ExportTypeIdentityMetadataName,
                                  AttributedModelServices.GetTypeIdentity(contractType));
                           return md;
                       });
        return new ExportDefinition[] {
             ReflectionModelServices.CreateExportDefinition(lazyMember, contracName, metadata, null)
        };
    }

    public override IQueryable<ComposablePartDefinition> Parts {
        get { return _parts.AsQueryable(); }
    }
}

Use it like this:

using (var myCatalog = new ConventionalCatalog()) {
    myCatalog.RegisterType<MyClass, IMyClass>();

    using (var container = new CompositionContainer(myCatalog)) {
        container.ComposeParts(this);
        ...
    }
}
adrianm
  • 14,468
  • 5
  • 55
  • 102