简体   繁体   中英

Generic Interface gets not imported with MEF RegistrationBuilder

I try to export the following interface:

public interface ITree<T> where T : IComparable

A class which implements the interface:

public class Tree<T> : ITree<T> where T : IComparable

In a Unit Test Class I do the following:

[TestClass]
public class TreeTest 
{
    [TestInitialize()]
    public void InitialTest()
    {
        RegistrationBuilder registrationITreeBuilder = new RegistrationBuilder();
        //export all classes which implement ITree
        registrationITreeBuilder.ForTypesMatching(t => t.GetInterface(typeof(ITree<>).Name) != null).Export<ITree<int>>();
        registrationITreeBuilder.ForType<TreeTest>().ImportProperty(p => p.TreeInstances,ib=>ib.AsMany(true)); //TreeTest - the unit test class

        var catalog = new AggregateCatalog(
            new AssemblyCatalog(Assembly.GetExecutingAssembly(), registrationTreeTestBuilder), //unit test project
            new AssemblyCatalog(typeof(ITree<>).Assembly, registrationITreeBuilder)
            );

        //Create the current composition container to create the parts
        var container = new CompositionContainer(catalog);
        container.ComposeParts(this);
    }
    public IEnumerable<ITree<int>> TreeInstances { get; set; }
}

After the InitialTest() method is executed the property TreeInstances is null . When adding the container to the watch, I see under container.Catalog.Parts

{Get.the.Solution.DataStructure.Tree({0})}

with the ExportDefinition (ContractName="Get.the.Solution.DataStructure.ITree(System.Int32)")} which should be correct. But there is no ImportDefinition although I set a ImportProperty definition.

Anyone know how to fix this?

The ComposeParts(...) call is actually meant to be used by the attributed programming model of MEF. What you are using in your unit test is using the convention based programming model.

Personally I would not mix those two, but if you want a quick fix here, you just add the [ImportMany] Attribute to your TreeInstances property and your test project will work.

I would suggest using a separate type here to host the tree instances, exporting it in your builder and getting it from your container in the test with an GetExportedValue call. This would mean your test class would look something like this:

[TestClass]
public class TreeTest
{
    private CompositionContainer _Container;

    private class Trees
    {
        public IEnumerable<ITree<int>> TreeInstances { get; set; }
    }

    [TestInitialize()]
    public void InitialTest()
    {
        ...
        //add the Export<Trees>() in your code
        registrationITreeBuilder.ForType<Trees>().ImportProperty(tt => tt.TreeInstances, ib => ib.AsMany()).Export<Trees>();
        ...
    }

    [TestMethod]
    public void TestMethod1()
    {
        var trees = _Container.GetExportedValue<Trees>();
    }
}

This way you could also add a cleanup method for your test to get rid of the CompositionContainer in case you allocated resources you need to dispose.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM