MEF in .NET 4.5






2.31/5 (6 votes)
Advancements in MEF in .NET 4.5.
Introduction
This article explains the problems with MEF1 and improvements in MEF2 (in .NET 4.5). Attached is a Visual Studio solution built in .NET 4.5.
Read the following articles for more on MEF:
MEF1
The primary focus of MEF1 was extensibility, MEF allows to create an application such that application's different parts can be extended like a plug-in.
MEF1 has some problems...
- There was no way exporting types without giving them export attribute. This limitation has two consequences:
- It was not possible to export types that you do not have access to the source code
- While converting one existing application into an extensible MEF application, first all types need to be decorated with export attribute
- Control lifetime of an instance, as MEF1 has only two instance scopes:
- per instance and
- shared global lifetime
- Composition problems were not easy to diagnose.
MEF2
MEF2 has solved the above problems:
- Attribute-less registration: One new class
RegistrationBuilder
is introduced that handles part creation and export registration automatically, it has solved both problems arising because the export attribute is required for type registration.RegistrationBuilder
introduced threeFor*()
methods as below that can identify/select parts to export.
ForType()
: selects a single type. In the code below, you can see how the typeAnniversaryGreetings
is exported and imported.//Export type regisBuilder.ForType<AnniversaryGreetings>().Export<AnniversaryGreetings>(); //import type var anniGreeting = container.GetExportedValue<AnniversaryGreetings>();
ForTypesDerivedFrom()
: selects types that are assignable to either a base class or an interface (the same asInheritedExport
in MEF1) . In the code below, you can see how all types derived fromIGreetings
are exported and imported.//Export all types derived from IGreetings regisBuilder.ForTypesDerivedFrom(typeof(IGreetings)) .SelectConstructor(cInfo => cInfo[0]) // this selects first constructor .Export<IGreetings>(); //Import types derived from IGreetings var v = container.GetExportedValues<IGreetings>();
ForTypesMatching(Predicate predicate)
: selects types that match a Boolean selector. This is the most flexible means of selection. In the code below, you can see how the type name matching "Greetings
" is exported and imported://Export types matching regisBuilder.ForTypesMatching(x => x.Name.Equals("HomeGreetings")).Export(); //import types var greetings = container.GetExportedValue<HomeGreetings>();
- Finer-Grained Control Over Lifetime
ExportFactory
improves granularity by allowing developers to create new instances of dependencies and control the lifetimes of the parts.ExportFactory<t>
can be exported which actually exports the typeT
, but it doesn’t create instance. Instance of the type will get created when it is accessed with methodExportCreator<t>.CreateExport()
.
The return value ofExportCreator<t>.CreateExport()
is aExportLifetimeContext<t>
.ExportLifetimeContext<t>
has a property called value that contains instance of the typeT
.ExportLifetimeContext<t>
also provides implementation ofiDisposable
, so instance can be cleaned when it is not required. In the code below, you can see how theExportFactory<t>
is used to export the type and create instance by callingCreateExport()
method.//Export factory class public class ExportFactoryExample { ExportFactory<Greetings> _factory; [ImportingConstructor] public ExportFactoryExample(ExportFactory<Greetings> factory) { _factory = factory; } public string Greeting(string name) { using (var instance = _factory.CreateExport()) { return instance.Value.Greet(name); } } } // export the ExportFactoryExample type regisBuilder.ForType<ExportFactoryExample>().Export<ExportFactoryExample>(); //import the ExportFactoryExample type var exportType = container.GetExportedValue<ExportFactoryExample>(); //CreateExport() method will be called on call of //Greeting method of ExportFactoryExample class exportType.Greeting(name);
ExportFactory v/s Lazy objects: The difference between
ExportFactory
and aLazy
object is that with theLazy
class, you can only create a single instance of the object. TheExportFactory
is a class that allows you to request a new instance of the type of object whenever you feel like it. - Diagnostics improvements: Two major improvements have been made to diagnostics.
CompositionOptions.DisableSilentRejection
parts with missing dependencies are identified and excluded from composition, which makes diagnostics hard in many cases. SpecifyingCompositionOptions.DisableSilentRejection
while constructing aCompositionContainer
will cause exceptions to be thrown when any composition problem occurs.container = new CompositionContainer (agrCatelog, CompositionOptions.DisableSilentRejection);
- Better exception messages MEF2 improves the way exception messages are formatted, presenting the most important information up-front.