MEF 2.0 – mini series: part 3 (Fluent import constructor)

2013/01/09

MEF 2.0 – mini series: part 3 (Fluent import constructor)

this is the 3rd post in the MEF 2.0 mini series.
you can see the following TOC for other posts in this series.

in this post I will discuss the fluent constructor injection API.

MEF, Import, Export, CompositionContainer, RegistrationBuilder, Catalog

Constructor Injection

the following code is having a Logger and Worker class which is having 2 constructor (one has no parameters and the other is getting ILogger):

Code Snippet
  1.  
  2. public class Logger: ILogger
  3. {
  4.     public void Write(string message) { /* … */}
  5. }
  6.  
  7. public class Worker
  8. {
  9.     private ILogger _logger;
  10.  
  11.     public Worker()
  12.     {
  13.         /* … */
  14.     }
  15.  
  16.     public Worker(ILogger logger)
  17.     {
  18.         _logger = logger;
  19.     }
  20. }

the question is, which of the construction will be invoked by the following code?

Code Snippet
  1. var picker = new RegistrationBuilder();
  2. picker.ForTypesDerivedFrom<ILogger>()
  3.     .Export<ILogger>();
  4. picker.ForType<Worker>()
  5.     .Export();
  6.  
  7. var catalog = new AssemblyCatalog(typeof(Program).Assembly, picker);
  8. var container = new CompositionContainer(catalog);
  9. container.Compose(new CompositionBatch());
  10. var w = container.GetExportedValue<Worker>();

the code Export the Logger and the Worker but doesn’t define explicitly which of the Worker’s construction should be invoke.

the answer is that it will invoke the constructor that is getting the ILogger parameter, but could we be more precise?

actually we do have 2 different options.

first option is to use SelectConstructor before the Export method.
see the following code:

Code Snippet
  1. var picker = new RegistrationBuilder();
  2. picker.ForTypesDerivedFrom<ILogger>()
  3.     .Export<ILogger>();
  4. picker.ForType<Worker>()
  5.     .SelectConstructor(builder => new Worker(builder.Import<ILogger>()))
  6.     .Export();
  7.  
  8. var catalog = new AssemblyCatalog(typeof(Program).Assembly, picker);
  9. var container = new CompositionContainer(catalog);
  10. container.Compose(new CompositionBatch());
  11. var w = container.GetExportedValue<Worker>();

this way we can define an expression that define which constructor should be invoke.
the expression is getting a ParameterImportBuilder which I used to define the logger (builder.Import<ILogger>()).

the next option is to set the SelectConstructor after the Export.
now we are getting a ConstructorInfo[] and we can select a single constructor out of this array.
ConstructorInfo

Code Snippet
  1. var picker = new RegistrationBuilder();
  2. picker.ForTypesDerivedFrom<ILogger>().Export<ILogger>();
  3. picker.ForType<Worker>()
  4.     .Export()
  5.     .SelectConstructor(ctors =>
  6.         ctors.First(info => info.GetParameters().Length == 1));

the code select a constructor which is having a single parameter, but the real implementation is up to you. you can ask on whatever constructor’s aspect which you like to.

Summary

as cool as it is to control the constructor injection using the fluent API,
you may consider to use imported properties rather than constructor injection because it can be more stable is during the composition state and can apply on more scenarios, including implementation of IPartImportsSatisfiedNotification.

Shout it

Add comment
facebook linkedin twitter email

Leave a Reply

Your email address will not be published.

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <s> <strike> <strong>

*

2 comments

  1. Celine Boston Bag2013/11/18 ב 19:17

    I not really know once you know it but I’m a bagaholic Kim, and this blog can be really useful for me.

    Reply
  2. abercrombie london2013/11/25 ב 08:59

    Abercrombie & Fitch: The Language of Fashion and Hate

    Reply