Adam Naylor
Adam Naylor

Reputation: 6330

How to list all types implementing an interface using MEF2?

When I call CompositionHost.GetExport<IInterface>("typename") I get an instance of the type requested which implements IInterface and everything is fine.

When I call CompositionHost.GetExports<IInterface>() I'm expecting a list of all the types that implement IInterface but the result is an empty collection.

Either I'm misunderstanding the purpose of GetExports() or I've implemented something incorrectly.

My conventions are built as follows:

conventions.ForTypesDerivedFrom<IInterface>()
           .Export<IInterface>(builder => builder.AsContractName(type => type.Name));

My types are implemented without attributes and just implement IInterface.

Is there a way to list types using MEF2 configured in this way? Or do I need to change something in order to achieve this?

Upvotes: 1

Views: 161

Answers (1)

dymanoid
dymanoid

Reputation: 15197

Exports are described by the export contracts.

The export contract is either a type or a type combined with a contract name. By using the ExportBuilder.AsContractName method, you explicitly specify the contract name. Thus, you can only import these parts by their type and contract name.

Your first option is: do not specify the contract name.

conventions.ForTypesDerivedFrom<IInterface>().Export<IInterface>();

Then, GetExports<IInterface>() will return all instances of that contract type. However, you will not be able to import a single instance via GetExport<IInterface>() because the container will throw an exception caused by multiple known implementations.

By the way, the container always returns instances. You write that you expect a list of types, but you only can get a list of instances (instantiated parts) from a container. To get a list of types, you need a catalog where the parts are managed. Depending on your environment, you might have no access to the catalog.

If you still want to have both features (multiple implementations and single implementation access), consider switching from contract names to metadata.

conventions
    .ForTypesDerivedFrom<IInterface>()
    .Export<IInterface>(builder => builder
        .AsContractType<IInterface>()
        .AddMetadata("ImplementationName", type => type.Name));

var myInstance = container
    .GetExports<Lazy<IInterface, IDictionary<string, object>>>()
    .Where(v => v.Metadata["ImplementationName"] == "YourImplType")
    .FirstOrDefault()?
    .Value;

IDictionary<string, object> is a generic metadata view that allows you to access the parts metadata.

Upvotes: 1

Related Questions