Search code examples
.net-coremefmef2

.net core MEF 2 NonShared Creation Policy


I am switching over to .net core and attempting to migrate my legacy framework MEF code to the new Microsoft Composition (MEF 2) (Microsoft.Composition 1.0.31).

We have several classes whose creation policy is "NonShared". I'm getting stuck on how I should apply the following attribute using MEF 2 with .net core:

[PartCreationPolicy(CreationPolicy.NonShared)]

Does anyone know what the .net core MEF 2 equivalent is for setting the above attribute to 'NonShared'?


Solution

  • Since only MEF 2 has been ported to .NET Core we only have access to types within System.Composition and not those in System.ComponentModel.Composition. Therefore it is not possible to set that attribute just the way you used to do with MEF 1.

    You can set the part creation policy for each export defined through the API though.

    Since we're near Halloween, let's suppose we have these classes:

    abstract class Monster { }
    
    class It : Monster { }
    
    class Zombie : Monster { }
    
    class Wife : Monster { }
    

    In MEF 2 you need to create a ConventionBuilder in order to define your exports, like this:

    var rules = new ConventionBuilder();
                rules.ForTypesDerivedFrom<Monster>()
                    .Export<Monster>();
    

    The interesting part here is that by default a Non Shared creation policy is enforced, so no need for the attribute. Let's test it:

    var config = new ContainerConfiguration()
                    .WithAssemblies(new[]{ typeof(Monster).GetTypeInfo().Assembly}, rules);
    
    var container = config.CreateContainer();
    var monsterA = container.GetExports<Monster>().First();
    var monsterB = container.GetExports<Monster>().First();
    Console.WriteLine(monsterA == monsterB);
    

    Now, since by default we do not enforce sharing in our exports this will write to the console False.

    In order to enforce sharing we simply add .Shared() to the methods chain after .Export<Monster> like this:

    rules.ForTypesDerivedFrom<Monster>()
                    .Export<Monster>()
                    .Shared();
    

    And if we run the test again we will get True since now both instances are pointing to the same reference.

    For composing parts you would do something like this:

    class TerrorContainer
        {
            [ImportMany]
            public IEnumerable<Monster> Monsters { get; set; }
        }
    

    And wherever you are composing you would write:

        var terrorContainer = new TerrorContainer();
        container.SatisfyImports(terrorContainer);