获取现有导出值/对象(不是获取或创建)的MEF方法是什么?

Gis*_*shu 5 mef c#-4.0

这就是我希望它如何工作的方式

container.GetButDoNotCreate<T>(); // should throw (or can return null) if container doesn't contain an instance matching the contract

var x = container.GetExportedValue<T>();

var y = container.GetButDoNotCreate<T>(); // should return the object created in previous step

Assert.That(x).IsSameAs(y);
Run Code Online (Sandbox Code Playgroud)

不同之处在于,如果容器不包含实例,则此方法不会创建实例.它是一个纯粹的get,如果它存在于容器中,请将此对象告诉我.我需要它用于我的测试,我不希望测试代码在生产容器中创建对象(如果它们没有创建)只使用现有的对象.只有生产代码才能向容器添加/删除对象.

发布到 MEF codeplex论坛但没有回复.所以希望SO上的某个人可能有答案.此外,如果我需要将该函数编写为扩展方法......那也可以作为答案.

Gil*_*les 1

这是我的解决方案。起初我尝试创建一个扩展方法。我尝试了几件事,阅读文档并探索了容器和目录上的可用属性、事件和方法,但我无法使任何工作发挥作用。

经过思考这个问题,我能想到的唯一解决办法就是创建一个基于 CompositionContainer 并实现 GetButDoNotCreate 方法的派生容器。

更新:我在发布后意识到该解决方案仅适用于您发布的简单示例,其中仅使用 GetExportedValue 来检索零件简单零件。除非您将容器用作没有 [Import] 的部件的简单服务定位器,否则在创建具有 [Import] 的部件时将不起作用。

这是实现:

using System;
using System.Collections.Generic;
using System.ComponentModel.Composition.Hosting;
using System.ComponentModel.Composition.Primitives;

namespace GetButNotCreate
{
    public class CustomContainer : CompositionContainer
    {
        private List<Type> composedTypes = new List<Type>();

        public CustomContainer(ComposablePartCatalog catalog)
            : base(catalog) 
        {
        }

        public new T GetExportedValue<T>()
        {
            if (!composedTypes.Contains(typeof(T)))
                composedTypes.Add(typeof(T));

            return base.GetExportedValue<T>();
        }

        public T GetButDoNotCreate<T>()
        {
            if (composedTypes.Contains(typeof(T)))
            {
                return base.GetExportedValue<T>();
            }

            throw new Exception("Type has not been composed yet.");
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

它的工作原理是重写 GetExportedValue 方法来跟踪迄今为止已组合的类型,然后使用它来检查 GetButNotCreate 中的类型组合。我抛出了一个异常,就像你在问题中提到的那样。

当然,您可能需要重写 GetExportedValue 的重载(除非您不使用它们,但即便如此,为了安全起见我还是会重写它们),并且如果您使用该类,可能还需要添加其他构造函数和其他内容。在这个例子中,我做了最少的工作来让它工作。

以下是测试新方法的单元测试:

using System.ComponentModel.Composition;
using System.ComponentModel.Composition.Hosting;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using System;

namespace GetButNotCreate
{
    public interface IInterface { }

    [Export(typeof(IInterface))]
    public class MyClass : IInterface 
    {
    }

    [TestClass]
    public class UnitTest1
    {      
        [TestMethod]
        [ExpectedException(typeof(Exception), "Type has not been composed yet.")]
        public void GetButNotCreate_will_throw_exception_if_type_not_composed_yet()
        {
            var catalog = new AssemblyCatalog(typeof(UnitTest1).Assembly);
            CustomContainer container = new CustomContainer(catalog);
            container.ComposeParts(this);

            var test = container.GetButDoNotCreate<IInterface>();
        }

        [TestMethod]
        public void GetButNotCreate_will_return_type_if_it_as_been_composed()
        {
            var catalog = new AssemblyCatalog(typeof(UnitTest1).Assembly);
            CustomContainer container = new CustomContainer(catalog);
            container.ComposeParts(this);

            var x = container.GetExportedValue<IInterface>();
            var y = container.GetButDoNotCreate<IInterface>();

            Assert.IsNotNull(y);
            Assert.AreEqual(x, y);
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

它表明,如果从未导出该类型,则 GetButNotCreate 将引发异常;如果已导入该类型,则 GetButNotCreate 将返回该类型。

我无法在任何地方找到任何钩子来检查(不诉诸反射)以查看 MEF 是否已组成一部分,因此这个 CustomContainer 解决方案将是我最好的选择。