这是我的解决方案。起初我尝试创建一个扩展方法。我尝试了几件事,阅读了文档并探索了容器和目录上的可用属性、事件和方法,但我无法使任何工作。
思考问题后,唯一能想到的办法就是创建一个基于 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.");
}
}
}
它通过重写 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);
}
}
}
它表明,如果该类型从未被导出,GetButNotCreate 将抛出异常,如果该类型已被导入,它将返回该类型。
我在任何地方都找不到任何钩子来检查(不借助反射)来查看 MEF 是否已组成部分,所以这个 CustomContainer 解决方案将是我最好的选择。