MEF lightweight adapters

Jan 21, 2011 at 2:10 PM
Edited Jan 26, 2011 at 7:46 AM

I find myself needing something like the lightweight adapters introduced in autofac 2.2 in MEF. I could probably just use Autofac and its MEF integration, but a MEF-only solution would be easier to sell to my colleagues. So my plan is (to try) to create an "AdaptingExportProvider" to add this feature.

Before I reinvent the wheel, has anyone in the MEF community already tried this?  Are there any known problems which make this difficult? Any suggestions for approaches?

update: I've created a first quick and dirty attempt which seems to work. At first I tried registering all adapters directly in the export provider in the style of Autofac, which worked but didn't feel very "MEFfy" because it centralizes the configuration of adapters. So now my approach is to export the adapter functions themselves as Func<object,object> with metadata indicating the original contract and the adapted contract. These adapter functions are then used by the ContractAdapterExportProvider to map existing exports into adapted ones.

Jan 25, 2011 at 3:10 PM

Interesting question.

Who isi exporting Func<object, object>? The command?

Are you sure you aren't trying too hard to mefify? Is there a reason you need the buttons in the container as opposed to creating them explicitly from a MEF retrieved list of commands (I understand why the commands need to be in the container) and calling SatisfyImports. Since you have a container creator anyway...

Jan 25, 2011 at 3:11 PM

Interesting question.

Who isi exporting Func<object, object>? The command?

Are you sure you aren't trying too hard to mefify? Is there a reason you need the buttons in the container as opposed to creating them explicitly from a MEF retrieved list of commands (I understand why the commands need to be in the container) and calling SatisfyImports. Since you have a container creator anyway...

Jan 25, 2011 at 5:22 PM
Edited Jan 25, 2011 at 9:01 PM
Is there a reason you need the buttons in the container as opposed to creating them explicitly from a MEF retrieved list of commands

Personally I'm not interested in adapting commands to buttons, that's just the example Nicholas picked to describe the feature. (I don't believe you can really do dynamic GUI composition on such a fine grained level.)

In the abstract, I'm trying to solve this problem:

  • I have a CatLibrary with a bunch of ICat exports.
  • I have a PetProgram with an ImportMany of IPet, let's say in a PetManager class.
  • CatLibrary does not know about PetProgram or the IPet interface. It is a reusable library independent of any application.
  • I wrote a CatToPetAdapter class to adapt any ICat to IPet.
  • I want each ICat export to be adapted into an IPet export, and I don't want to do any extra work each time a new ICat export is added.

Of course, I could always change my PetManager class to ImportMany both IPet and ICat, and add the adapter logic inside it. But I don't want that class to know about ICat or its adapter, that's the whole point of the IPet interface. It hides the implementation specifics so that my PetManager only needs to know how to deal with IPet.

Who isi exporting Func? The command?

A separate class. There would be many commands but only one adapter export for all those commands.

Jan 31, 2011 at 5:38 PM

I don't see an elegant way to do this. Maybe someone else will.

If I needed to do this, I would probably have the PetProgram import a PetFactory and the PetFactory which would have an ImportMany of ICat and the adapter. I think this brute force approach does not provide the abstraction you want.

You could get closer by having the PetFactory import a series of PetFactory[Provider/Adapter] each of which had an ImportMany of ICat (or IDog) and then adapted to IPet and was capable of producing IPets. This would leave the PetFactory with something like this pseudo-code (in a non-LINQed out version for clarity):

[ImportMany]
private IEnumerable(IPetProviders )_petProviders;
IEnumerable<IPet> GetAllPets()
   var ret = new List<IPet>();
   foreach(var adapter in _petProviders)
   { 
       foreach (var pet in adapter.GetPets)
       { ret.Add(pet); }
   }
   return ret;
}

and of course the calling program would need to import the factory and call the method instead of a direct ImportMany.

Kathleen
     

Feb 12, 2011 at 3:05 AM

Meanwhile I discovered that there was a AdaptingExportProvider up to MEF Preview 5. In a blog post announcing MEF Preview6, Nicholas states that "Contract Adapters have been removed". I am not sure why there isn't even a sample remaining.

 

Feb 12, 2011 at 4:15 AM
We ripped adapters which were part of MEF. Introducing stable composition broke our contract adapter implementation beyond repair.

Sent from my Windows Phone

From: wcoenen
Sent: Friday, February 11, 2011 7:05 PM
To: Glenn Block
Subject: Re: MEF lightweight adapters [MEF:242753]

From: wcoenen

Meanwhile I discovered that there was a AdaptingExportProvider up to MEF Preview 5. In a blog post announcing MEF Preview6, Nicholas states that "Contract Adapters have been removed". I am not sure why there isn't even a sample remaining.