我有两个ISchedulerProvider
接口的实现,一个用于测试目的,一个用于非测试执行(Lee Campbell的Intro to Rx的赞美)。我想通过MEF导出两个实例并处理导入,如果我检测到我在测试环境中,请使用测试调度程序,如果我不是,则使用另一个。
我可以在每次导出时设置元数据,在我使用带有相应过滤器的[ImportMany]
的任何地方使用ISchedulerProvider
,但这似乎是很多开销。有没有办法在课堂建设之前有条件地选择出口?
一个简单的例子非常有用,特别是如果解决方案涉及类似于导出提供程序的东西。
答案 0 :(得分:1)
我能够通过创建一个继承自CompositionContainer的类来完成此任务,该类根据自定义属性过滤掉导出。
这是一个我被抛在一起的例子:
实施的界面
public interface ISchedulerProvider
{
string Foo { get; }
}
用于保存目标环境信息的自定义属性,我在此示例中使用了字符串,但我可能在生产代码中使用了Enum:
public class EnvironmentSpecificAttribute : Attribute
{
public string TargetEnvironment { get; }
public EnvironmentSpecificAttribute(string targetEnvironment)
{
TargetEnvironment = targetEnvironment;
}
}
示例实施:
[EnvironmentSpecific("QA")]
[Export(typeof(ISchedulerProvider))]
public class TestProvider : ISchedulerProvider
{
public string Foo { get; } = "TestBar";
}
[EnvironmentSpecific("Prod")]
[Export(typeof(ISchedulerProvider))]
public class RealProvider : ISchedulerProvider
{
public string Foo { get; } = "RealBar";
}
要使用接口的类:
[Export]
public class Consumer
{
private readonly ISchedulerProvider _schedulerProvider;
[ImportingConstructor]
public Consumer(ISchedulerProvider schedulerProvider)
{
_schedulerProvider = schedulerProvider;
}
public string GetFoo()
{
return _schedulerProvider.Foo;
}
}
自定义CompositionContainer:
public class EnvironmentSpecificContainer : CompositionContainer
{
private readonly string _targetEnvironment;
public EnvironmentSpecificContainer(ComposablePartCatalog catalog, string targetEnvironment, params ExportProvider[] providers) : base(catalog, providers)
{
_targetEnvironment = targetEnvironment;
}
protected override IEnumerable<Export> GetExportsCore(ImportDefinition definition, AtomicComposition atomicComposition)
{
return base.GetExportsCore(definition, atomicComposition)?.Where(IsForEnvironmentOrEnvironmentNotSpecified);
}
private bool IsForEnvironmentOrEnvironmentNotSpecified(Export export)
{
EnvironmentSpecificAttribute attribute = export.Value.GetType().GetCustomAttribute<EnvironmentSpecificAttribute>() as EnvironmentSpecificAttribute;
return attribute == null || string.Equals(attribute.TargetEnvironment, _targetEnvironment,
StringComparison.InvariantCultureIgnoreCase);
}
}
最后,使用上面的类:
static void Main(string[] args)
{
string environmentName = "QA";
EnvironmentSpecificContainer container = new EnvironmentSpecificContainer(new AssemblyCatalog(Assembly.GetCallingAssembly()), environmentName);
var tmp = container.GetExportedValue<object>("MefTest.Consumer");
}