Are MEF exports cached or discovering every time on request? Are MEF exports cached or discovering every time on request? wpf wpf

Are MEF exports cached or discovering every time on request?


will MEF do global lookup again or it caches somewhere internally

Yes, MEF perfoms some caching and widely uses lazy initialization, if you question is about MEF performance:

1) metadata (composable parts, export definitions and import definitions) is cached. Example:

public override IEnumerable<ExportDefinition> ExportDefinitions{    get    {        if (this._exports == null)        {            ExportDefinition[] exports = this._creationInfo.GetExports().ToArray<ExportDefinition>();            lock (this._lock)            {                if (this._exports == null)                {                    this._exports = exports;                }            }        }        return this._exports;    }}

2) exported values are cached too:

public object Value{    get    {        if (this._exportedValue == Export._EmptyValue)        {            object exportedValueCore = this.GetExportedValueCore();            Interlocked.CompareExchange(ref this._exportedValue, exportedValueCore, Export._EmptyValue);        }        return this._exportedValue;    }}

Of course, when using CreationPolicy.NonShared, exported value becomes created again and again, when you requesting it. But even in this case "global lookup" isn't performed, because metadata is cached anyway.


It does a lookup every time, when you use [PartCreationPolicy(CreationPolicy.NonShared)]. You then have to implement the caching yourself.

The default implementation is using a Singleton pattern. This equals the attribute [PartCreationPolicy(CreationPolicy.Shared)]. This is the best practice.

For more information, read http://blogs.microsoft.co.il/blogs/bnaya/archive/2010/01/09/mef-for-beginner-part-creation-policy-part-6.aspx


Although the values/metadata might be partially cached, doing some performance testing shows that some lookup is performed every time a call to GetExportedValue is made. So if you have many calls where you need to get the value, you should do the caching yourself.

namespace MEFCachingTest{    using System;    using System.ComponentModel.Composition;    using System.ComponentModel.Composition.Hosting;    using System.ComponentModel.Composition.Primitives;    using System.Diagnostics;    using System.Reflection;    public static class Program    {        public static CompositionContainer Container { get; set; }        public static ComposablePartCatalog Catalog { get; set; }        public static ExportedClass NonCachedClass        {            get            {                return Container.GetExportedValue<ExportedClass>();            }        }        private static ExportedClass cachedClass;        public static ExportedClass CachedClass        {            get            {                return cachedClass ?? (cachedClass = Container.GetExportedValue<ExportedClass>());            }        }        public static void Main()        {            Catalog = new AssemblyCatalog(Assembly.GetExecutingAssembly());            Container = new CompositionContainer(Catalog);            const int Runs = 1000000;            var stopwatch = new Stopwatch();            // Non-Cached.            stopwatch.Start();            for (int i = 0; i < Runs; i++)            {                var ncc = NonCachedClass;            }            stopwatch.Stop();            Console.WriteLine("Non-Cached: Time: {0}", stopwatch.Elapsed);            // Cached.            stopwatch.Restart();            for (int i = 0; i < Runs; i++)            {                var cc = CachedClass;            }            stopwatch.Stop();            Console.WriteLine("    Cached: Time: {0}", stopwatch.Elapsed);        }    }    [Export]    [PartCreationPolicy(CreationPolicy.Shared)]    public class ExportedClass    {    }}

For more variations, look at this gist: https://gist.github.com/DanielRose/d79f0da2ef61591176ce

On my computer, Windows 7 x64, .NET 4.5.2:

Non-Cached: Time: 00:00:02.1217811    Cached: Time: 00:00:00.0063479

Using MEF 2 from NuGet:

Non-Cached: Time: 00:00:00.2037812    Cached: Time: 00:00:00.0023358

In the actual application where I work, this made the application 6x slower.