Can I parameterize MEF imports?

I am relatively new to MEF, so I do not fully understand the possibilities. I am trying to achieve something similar to Unity InjectionMember.

Let's say I have a class that imports MEF parts. For simplicity, we take the following class as the exported part.

[Export] [PartCreationPolicy(CreationPolicy.NonShared)] public class Logger { public string Category { get; set; } public void Write(string text) { } } public class MyViewModel { [Import] public Logger Log { get; set; } } 

Now I'm trying to figure out if it is possible to specify the value of the Category property when importing. Something like:

 public class MyViewModel { [MyImportAttribute(Category="MyCategory")] public Logger Log { get; set; } } public class MyOtherViewModel { [MyImportAttribute(Category="MyOtherCategory")] public Logger Log { get; set; } } 

I am currently implementing IPartImportsSatisfiedNotification and setting up a category in code. But obviously, I would rather keep everything neat in one place.

+3
composition mef
source share
2 answers

After more delving into the MEF, there seems to be no way to do this declaratively. Although you can get your own export attributes, there is no mechanism to get the import attribute in any meaningful way.

But instead of implementing IPartImportsSatisfiedNotification, what I can do (it seems obvious now) is setting a category in setter. I have to give up automatic properties, but what a life.

 public class MyViewModel { private Logger log; [Import] public Logger Log { get { return log; } set { log = value; log.Category = "MyCategory"; } } } 
+3
source share

In the MEF Programming Guide , read the Export and Metadata section. It shows how you can add metadata to the exported part using the ExportMetadata attribute or defining your own custom export attribute.

You can then define the ILoggerMetadata interface as follows:

 public interface ILoggerMetadata { string Catagory { get; } } 

and execute ImportMany a IEnumerable<Lazy<ILogger,ILoggerMetadata>> and select the one you want in the code, for example:

 private ILogger fooLogger; [ImportMany] public IEnumerable<Lazy<ILogger,ILoggerMetadata>> Loggers { set { this.fooLogger = value.First(x => x.Metadata.Catagory == "foo").Value; } } 

I agree that it would be better to put metadata restrictions directly in the import attribute, but this is currently not possible in the MEF out of the box. (It may be possible to extend the MEF for this.)

Another approach is to output the IFooLogger interface from ILogger and use this in your import and export. It is simple and has the same effect as import restrictions. However, this approach does not work if you have several metadata attributes and / or many possible values.

edit: I subtly misunderstood your question; I thought that this was due to the restriction of imports, and not with the configuration of the imported object with some additional parameters.

I think this recent article from Kathleen Dollard addresses the same issue. Also, in this post about component relationships , Nicholas Bloomhardt models such a โ€œparameterizationโ€ as an injection of Func<X,Y> (or Func<ILogger,string> in your case).

You can do the same in MEF by placing the [Export(typeof(Func<ILogger,string>))] attribute directly on the method. Or, if you need a less ambiguous contract, you can define an ILoggerFactory interface and import / export, which:

 public ILoggerFactory { ILogger Create(string category); } 

In the end, you still have to call factory in the code.

+5
source share

All Articles