Search code examples
c#meffactory-pattern

Factory pattern with Managed Ext Framework (MEF)


I am trying to implement Factory Pattern with MEF.

Here is my solution

Core Project

IClass
ObjectFactory static Class(This is where the problem is)

Project A

[Export(typeof(IClass))]
[ExportMetadata("Type", "TypeA")]
public classA : IClass
{}

ProjectB

[Export(typeof(IClass))]
[ExportMetadata("Type", "TypeB")]
public classB : IClass
{}

I am facing problem when I am trying to create object dynamically

And here is factory class:

public static class ObjectFactory
{
    private static readonly CompositionContainer _container;

    [ImportMany]
    public static IEnumerable<Lazy<IClass, IMetaData>> objectTypes;
    static ObjectFactory()
    {
        AggregateCatalog catalog = new AggregateCatalog();

        catalog.Catalogs.Add(new DirectoryCatalog(Environment.CurrentDirectory));
        _container = new CompositionContainer(catalog);

        try
        {
            objectTypes = _container.GetExports<IClass, IMetaData>();
        }
        catch (CompositionException compositionException)
        {
            Console.WriteLine(compositionException.ToString());
            Console.ReadLine();
        }
    }

    public static IClass CreateObject(ObectType objectType)
    {
        IClass outProvider;

        Type typeToLoad = objectTypes.Where(x => x.Metadata.Type == objectType.ToString()).FirstOrDefault().GetType();
        outProvider = (IClass)Activator.CreateInstance(typeToLoad);

        return outProvider;
    }
}

Solution

  • If you want a new "NonShared" instance provided on every call to CreateObject then I suggest this refactoring.

    private static readonly CompositionContainer _container;
    
    static ObjectFactory()
    {       
        var directoryCatalog = new DirectoryCatalog(Environment.CurrentDirectory)
        _container = new CompositionContainer(directoryCatalog);        
    }
    
    public static IClass CreateObject(ObectType objectType)
    {       
        var objectTypes objectTypes = new List<Lazy<IClass, IMetaData>>();
        try
        {
           objectTypes.AddRange(_container.GetExports<IClass, IMetaData>());
        }
        catch (CompositionException compositionException)
        {
            Console.WriteLine(compositionException.ToString());
            Console.ReadLine();
        }
    
        return objectTypes.FirstOrDefault(x => x.Metadata.Type == objectType.ToString());
    }
    

    You see MEF will resolve new instances (non shared ones that is) every time it composes types or you you call GetExports (and all other overload of this function). Alternatively you can export IClass factories instead, then you will have a collection of there providers.

    P.S. [ImportMany] on objectTypes member in your example is superfluous, since you are not composing this type (I don't believe you even can since its static), you are simply setting it programmatically from the output of GetExports