That is he wants to export a generic IDomainController with the idea the closed generic versions like IDomainController<Customer> could be imported.

He also rightly observed that many of the IoC containers that exist support this functionality including Unity. (I chuckled when I heard that because I was in p&p when we first wrote Unity) However, it is a valid question, why don’t we support it? This is one of those questions that I, Hammett and Nick all asked when we joined the team. We do support closed generics without a problem, but not open. Why?

As you dig into the details, it quickly becomes clear. The root of the answer is that MEF is not type based, it is contract based. Below are the details from my response…

MEF parts relate on contracts which are strings, not types. To illustrate, see the code below.

namespace Orders {

publicinterface IOrderRepository {}

[Export(typeof(IOrderRespository))]

publicclass OrderRepository : IOrderRepository {

}

}

Although I have passed typeof(IOrderRepository) to the export, that is just a convenience that gets converted to a contract name of “Orders.IOrderRepository”. The same applies to the importer…

[Export]

publicclass OrderService(

[Import]

public IOrderRepository Repository {gets;set;}

)

The import on IOrderRepository also gets converted to a contract name of “Orders.IOrderRepository”. During composition, the container is able to satisfy the import as the 2 contracts match. In the same way we support closed generics, so this code….

publicinterface IRepository<T> {}

[Export(typeof(IRepository<Order>))]

publicclass OrderRepository : IRepository<Order> {

}

[Export]

publicclass OrderService(

[Import]

public IRepository<Order> Repository {gets;set;}

)

will work because the OrderRepository is exporting the contract name “Orders.IRepository<Order>” and the OrderService is importing the same contract.

However, this is what it looks like if we try the same with open generics.

publicinterface IRepository<T> {}

namespace Utils {

[Export(typeof(IRepository<>))]

publicclass Repository : IRepository<T> {

}

}

[Export]

publicclass OrderService(

[Import]

public IRepository<Order> Repository {gets;set;}

)

Now the contract names will be different. The exporter will have a contract of “Utils.IRepository<>” and the importer will have a contract of “Utils.IRepository<Order>”.

It is a simple match up, that breaks down in the open-generics case. This is because fundamentally, MEF is not matching on type.

There are theoretical ways to address it, but they are all very ugly, require a lot of string parsing and really go against the grain of MEF’s core design.

What you are talking about with generics, abstractly I guess is variants, would it not be possible to design the strings to be less ‘dumb’, and support variance? this way you can say.. we didn’t add generics support specifically, we added variant support and mapped generics to that ;).

But perhaps you are right, this isn’t something that MEF supports, and you certainly need a set of opinions to stand by otherwise you’ll end up with a cluttered mess thats been pulled each way to fit uncertain requirements.

http://www.codebetter.com/blogs/glenn.block/ Glenn Block

Hi Torkel

Dynamic languages are one instance, though there are others like supporting Xaml etc.

In terms of limiting, the question is HOW is it limiting for extensibility scenarios. Yes IoC containes support it, but give me scenarios where you absolutely can’t live with out it.

http://www.codinginstinct.com Torkel

The idea to have contracts represented as strings seems to be a big limitation, I understand the reasoning (to be able to support dynamic languages).

http://www.codebetter.com/blogs/glenn.block/ Glenn Block

Hi Rob.

Actually in our next drop we do allow you to harden contacts to say that the implementer must be of a certain type. We call this feature Typed Imports/Exports. Using Typed I/E you can still use string contracts, but you can add additional constraints on the actual type. The Export and Import attribute get an additional overload to allow specifying Contract Name AND Type. By default if you just specify a type, then we will use the type for contract name as before, and we will also constrain on that type.

When last I looked into the MEF source, I noticed that contract was essentially a string, and that you had a handful of helper methods surrounding it. This alarmed me quite a bit. I meant to talk with you about this at ALT.NET. Here’s the thought. If contract is such a core concept, why does it exist only implicitly as a string? You should really consider creating an IContract interface with several implementations (maybe you had this and I just missed it, but…) You could then come up with a more elegant solution to the above problem. Even if you don’t support open generics at any point, it still might be valuable to make the idea of contract more explicit.