Search code examples
c#.netinversion-of-controlmef

exporting two instances of generic type


Maybe I am too hard to myself, but I really want to know this. I have one really naughty constructor so I thought I could use MEF and make my life simple. But I wasn't right. I really used google, but all I found was nothing compared to this.

I have a constructor like this:

public BussinesProcessLoader(ILoader<List<Resource>> resourceLoader, ILoader<List<Project>> projectsLoader)
{
    this.resourceLoader = resourceLoader;
    this.projectsLoader = projectsLoader;
}

Now I want to use MEF and let it compose BussinesProcessLoader like this:

new BussinesProcessLoader(new Loader<List<Resource>>(new Projects.Deserializer.ResourceDeserializer(), fileResolver), new Loader<List<Project>>(new ProjectsDeserializer(), fileResolver))

So I found out I am not able to Export two instances of class like this one:

internal class Loader<T> : ILoader<T>
{
    public Loader(IDeserializer<T> deserializer, FileResolver fileResolver)
    {
        this.Deserializer = deserializer;
        this.FileResolver = fileResolver;
    }

    public IDeserializer<T> Deserializer { get; set; }

    public FileResolver FileResolver { get; set; }

    ...
}

I would need two different ImportingConstructor attributes and two Exports with contractName...

...and modify constructor of BussinesProcessLoader like this:

[ImportingConstructor]
public BussinesProcessLoader([Import("ResourceLoader")] ILoader<List<Resource>> resourceLoader, [Import("ProjectsLoader")] ILoader<List<Project>> projectsLoader)
{
    this.resourceLoader = resourceLoader;
    this.projectsLoader = projectsLoader;
}

Is it even possible to accomplish this? Any help would be appreciated.


Solution

  • I think you'll need two different concrete classes for your exports:

    [Export(typeof(ILoader<List<Resource>>))]
    internal class ResourceLoader : Loader<List<Resource>>
    {
       [ImportingConstructor]
       public ResourceLoader(IDeserializer<List<Resource>> deserializer, FileResolver fileResolver) : base(deserializer, fileResolver)
       {
       }
    }
    
    [Export(typeof(ILoader<List<Project>>))]
    internal class ProjectLoader : Loader<List<Project>>
    {
       [ImportingConstructor]
       public ProjectLoader(IDeserializer<List<Project>> deserializer, FileResolver fileResolver) : base(deserializer, fileResolver)
       {
       }
    }
    

    You'll need to add an [ImportingConstructor] attribute to your BussinesProcessLoader constructor, but you won't need the [Import("...")] attributes on the parameters.