Inheriting Exported methods - Possible?

Dec 31, 2009 at 1:25 PM

Hi.  I've been playing around with preview 8 and one thing I tested for curiosity sake is whether this is possible:

class SomeTool
    public void DoSomeWork() {...}

class SomeDerivedTool : SomeTool
    public void DoSomeOtherWork() {...}

//Now, get all the actions from a specific instance of a tool 
//so I can show it in a menu or something
class ActionsHolder
    public Lazy<Action, ISomeMetadata>[] AllActions { get; set; }

    var catalog = new TypeCatalog(typeof(SomeDerivedTool));
    var container = new CompositionContainer(catalog);

    var holder = new ActionsHolder();

    AddActionsToMenu(holder.AllActions );  //The metadata would have things like display name, icon, etc.

I expected that all the exported functions on SomeDerivedTool (it has 2 public methods) would be imported, but I only see 1 function instead of 2.  The behavior is the same if I do
container.ComposeParts(holder, new SomeDerivedTool());

I dug around the framework code and found out how the base class's exports were being ignored (AttributedPartCreationInfo.cs line 267:  BindingFlags flags = BindingFlags.DeclaredOnly |...) but I don't know why that is the desired behavior.  I can guess that doing an import from a directory of assemblies could result in a lot of extra imports (I'd get three imported methods if the catalog was an AssemblyCatalog above, instead of the 2 the current implementation loads).  Also, if the base class were abstract, its export would not be discovered at all.

It might be a handy thing to allow though.  I honestly don't have a real use case right now, so I was just exploring out of curiosity.  I'll update this discussion if I do run across a real need to export the methods from the base.

I also modified the framework code a little (commented out the DeclaredOnly) and I got the behavior I was looking for.  Also, all 1500+ unit tests still passed.  That was pleasing to see, but made me a little uneasy - are the tests covering all the bases?





Jan 1, 2010 at 9:30 AM

No, we dont' allow method exports to be inherited, we only allow class level exports to be inherited through the usage of InheritedExport. The reason we do not allow members is we determined it was too costly, as we would have to look at almost every member to see if it had an InheritedExport, as we support exports on fields, properties and methods. At the class level we were able to do it in a fashion that didn't significantly impact perf as it was a single place and there was a cheap way of figuring out whether the InheritedExport was present.

We are currently planning our next version of MEF, I will add this to the backlog of things for us to look into in vNext. For now you can have method exports on the base, and re-export them in the overridden class.

Hope this helps