Export is there but ExportFactory is not?

Jul 22, 2010 at 6:50 AM
Edited Jul 22, 2010 at 11:34 AM

Why would this work:

var entity1 = Container.GetExportedValue<MyEntity>();

...but not...

var entity2 = Container.GetExportedValue<ExportFactory<MyEntity>>();

I can't figure out why. I just get this error. And it's true that there is no such part, but this has always worked before. I should be able to pull on my export as an ExportFactory`1 without making any changes as long as the PartCreationPolicy is anything but Shared, which it is. I'm using the MEF 2 Preview getting the 404 equivalent of MEF.

No exports were found that match the constraint '((exportDefinition.ContractName = "System.ComponentModel.Composition.ExportFactory(MyEntity)") && (exportDefinition.Metadata.ContainsKey("ExportTypeIdentity") && "System.ComponentModel.Composition.ExportFactory(MyEntity)".Equals(exportDefinition.Metadata.get_Item("ExportTypeIdentity"))))'.

Any advice on how to debug this?

Jul 22, 2010 at 12:41 PM

I believe the answer for the above is that you just can't do it. Found this thread by Wes - "You cannot get an ExportFactory back from a direct query on the container"

So i figured maybe I could do this:

    [Export]
    public class Factory<T>
    {
        public IEnumerable<ExportFactory<T>> Factories { get; private set; }

        [ImportingConstructor]
        public Factory(IEnumerable<ExportFactory<T>> factories)
        {
            this.Factories = factories;
        }
    }

I was then reminded that MEF does not support open generic types. Which this is. And while on that topic. Can we expect open generic type support in the near future? I know that Glenn blogged about this but then I have to grab that from MEF Contrib and I want to avoid that. Is there maybe some other way I can leverage this in a generic fashion? So that in the end, I can do:

container.GetExport<Factory<T>>();

...and it will work! I should already be able to do this but it will have to create a strongly typed object for each type which seems a bit verbose.

Jul 22, 2010 at 6:52 PM
Edited Jul 22, 2010 at 6:54 PM

You can do it with some slight modification to your approach by making it a buddy part. 

public class Factory<T> { 
  [ImportMany] 
  public IEnumerable<ExportFactory<T>> Factories { get; set; } 
} 

Now you can new up a closed instance of Factory<T> and call SatisfyImportsOnce on the container to get the factories. 

var factory = new Factory<Foo>(); 
container.SatisfyImportsOne(factory); //satisfies the factories import

 I haven't tested this exactly, but it should work. The reason why this is needed is because ExportFactory relies on a specific ImportDefinition that we create under the hood for imports on parts. This works because in this case we dynamically create an import of ExportFactory. Glenn

Jul 22, 2010 at 6:55 PM
Edited Jul 22, 2010 at 6:58 PM

Oh yeah, that should work, I'll try that, thanks!

I just know there were line breaks in that post that went missing ;) There's something wierd about these forms... your post when I first read it was a giant single paragraph blob.

Jul 22, 2010 at 6:58 PM

Try refreshing on codeplex..>I fixed the breaks

Jul 22, 2010 at 6:59 PM

Yeah, it's all good now :)