Search code examples
c#wpfmvvmmefcaliburn.micro

Using MEF to Import Types that Inherit from a given Interface


[Note there are questions around this subject, but none that seemingly match this specific case]

I have two ViewModels that export their own interface types

[Export(typeof(ITestExplorer))]
public class TestExplorerViewModel : Tool, ITestExplorer, IDataErrorInfo, IDisposable
{
    // Implementation.
}

and

[Export(typeof(ITicker))]
public class TickerViewModel : Tool, ITicker, IDataErrorInfo
{
    // Implementation.
}

Where ITicker and ITestExplorer both inherit from the same ICoreDataProvider interface

public interface ITicker : ITool, ICoreDataProvider { }

and

public interface ITestExplorer : ITool, ICoreDataProvider { }

I am aware that these two interfaces are essentially the same, however, they are required as I am using Caliburn micro to launch certain view types with different classes inheriting from each of the above.

My problem is that I wish to [ImportMany] ICoreDataProviders, but I can't export the above classes as both ITicker and ICoreDataProvider (or ITestExplorer and ICoreDataProvider) [multiple exports in a single attribute]. I want to do

[ImportMany]
private IEnumerable<IBetDataProvider> dataProviderCollection;

but I can't switch my export types to ICoreDataProvider as they are currently used to launch views ect.

  1. Can I ask MEF to import "all type that implement ICoreDataProvider", or does the export have to be explicit?
  2. If the answer to the above is "yes", how? If "no", is there another way using MEF?

I am aware I could fudge this using reflection via something like

var instances = 
    from t in Assembly.GetExecutingAssembly().GetTypes()
    where t.GetInterfaces().Contains(typeof(ISomething))
         && t.GetConstructor(Type.EmptyTypes) != null
    select Activator.CreateInstance(t) as ISomething;

But I don't like this because I will need all sorts of checks on whether the view is open etc.

Thanks for your time.


Solution

  • I can't export the above classes as both ITicker and ICoreDataProvider ... [multiple exports in a single attribute]

    You can export them as both interfaces, just add the export attribute twice.

    [Export(typeof(ITestExplorer))]
    [Export(typeof(ICoreDataProvider))]
    public class TestExplorerViewModel : Tool, ITestExplorer, IDataErrorInfo, IDisposable
    {
        // Implementation.
    }
    
    [Export(typeof(ITicker))]
    [Export(typeof(ICoreDataProvider))]
    public class TickerViewModel : Tool, ITicker, IDataErrorInfo
    {
        // Implementation.
    }