Search code examples
c#genericsdelegatesmefconstructor-injection

Can MEF resolve a Func delegate returning an interface?


Code at bottom is from a working WPF sample application that used Autofac for dependency injection. I want to convert to latest version of MEF instead. I also have NuGet packages CommonServiceLocator (V. 1.3) and Prism.Core, Prism.Mef and Prism.Wpf (all 6.1) installed. When I do

var provider = ServiceLocator.Current.GetInstance<FriendDataProvider>();

I get an ActivationException from the "Func..." declaration in the constructor of FriendDataProvider. Can MEF do this at all? If yes, what attribute declarations are required?

[Export]
public class FriendDataProvider
{
    private readonly Func<IDataService> _dataServiceCreator;

    [ImportingConstructor]
    public FriendDataProvider(Func<IDataService> dataServiceCreator) // <= DI ERROR
    {
        _dataServiceCreator = dataServiceCreator;
    }

    public void DoSomething()
    {
        using (var service = _dataServiceCreator()) // Factory
        {            }
    }
}

[Export(typeof(IDataService))]
public class DataService : IDataService
{
    public ClassA GetSomething()
    {
        return new ClassA();
    }

    public void Dispose()
    {        }
}


public interface IDataService : IDisposable
{
    ClassA GetSomething();
}

public class ClassA
{ }

Solution

  • Most likely you are looking for MEF ExportFactory class: https://msdn.microsoft.com/en-us/library/ff382807(v=vs.110).aspx

    It'a a mixture of Owned<> and Func<> ideas from AutoFac. Mind that ExportFactory.CreateExport returns ExportLifetimeContext which is Disposable. Disposing the export lifetime context will also dispose the injected part + all its dependencies. ExportFactory behavior is slightly different depending on Instancing mode of the owner part. If the owner class is a singleton ExportFactory will always create you new instance (behaves like Func< Owned< T>> in Autofac), but if you use it in combination with CompositionScopes you'll get behavior similar to Func< T> in AutoFac. See example: http://blogs.microsoft.co.il/bnaya/2013/01/16/mef-20-mini-series-part-6-composition-scoping-and-lifetime-management/

    Here is your example re-written using ExportFactories:

       [Export]
    public class FriendDataProvider
    {
        private readonly ExportFactory<IDataService> _dataServiceCreator;
    
        [ImportingConstructor]
        public FriendDataProvider(ExportFactory<IDataService> dataServiceCreator) // <= DI ERROR
        {
            _dataServiceCreator = dataServiceCreator;
        }
    
        public void DoSomething()
        {
            using (var service = _dataServiceCreator.CreateExport()) // Factory
            {
    
            }
        }
    }
    
    [Export(typeof(IDataService))]
    public class DataService : IDataService
    {
        public ClassA GetSomething()
        {
            return new ClassA();
        }
    
        public void Dispose()
        { }
    }
    
    
    public interface IDataService : IDisposable
    {
        ClassA GetSomething();
    }
    
    public class ClassA
    { }