C# 如何替换MEF容器中的导出零件/对象?

C# 如何替换MEF容器中的导出零件/对象?,c#,.net,mef,C#,.net,Mef,我有一个WPF应用程序正在运行,它需要影响UI的所有操作都在UI线程上。WPF还提供了一个Dispatcher类来处理这个问题,所以我将其提取到一个依赖项中 public interface UIActionExecutor { void Do(Action action); } 因此,在我的生产代码中,我使用了一个导出的实现,该实现委托给WPF调度程序。我用MEF来表示DI 现在的问题是,在我的验收测试中,我需要用模拟替换容器中响应UIActionExecut

我有一个WPF应用程序正在运行,它需要影响UI的所有操作都在UI线程上。WPF还提供了一个Dispatcher类来处理这个问题,所以我将其提取到一个依赖项中

public interface UIActionExecutor
    {
        void Do(Action action);
    }
因此,在我的生产代码中,我使用了一个导出的实现,该实现委托给WPF调度程序。我用MEF来表示DI

现在的问题是,在我的验收测试中,我需要用模拟替换容器中响应
UIActionExecutor
的部分/对象。因此,我需要使用wpfdispatcher从容器中删除
executor
,并在其位置添加
MockUIActionExecutor
。这听起来很简单(如果我没有使用MEF的话)。。。但我的搜索技能并没有帮助我找到如何使用MEF容器的答案

更新: 如果有人想知道解决方案的工作原理,请阅读。这就是我最后使用的

    var defaultExportProvider = new CatalogExportProvider(__defaultCatalog);
    var catalogOfMocks = new AssemblyCatalog(assemblyExportingMocks);
    // order of params important (precedence left to right)
    __container = new CompositionContainer(catalogOfMocks, defaultExportProvider);
    defaultExportProvider.SourceProvider = __container

DI容器负责将所有内容连接在一起

单元测试负责单独测试单个代码单元。模拟用于替换依赖项。因此,原则上,DI容器不应用于单元测试。它与“单元测试”的定义相矛盾

然而,我可以肯定地理解,除了单元测试之外,您可能还希望进行自动化集成测试,并且您可能希望在这样的测试中使用MEF来替换某些MEF部分。您可以这样做:

// first set up the main export provider
var mainCatalog = new AggregateCatalog(...); 
var mainExportProvider = new CatalogExportProvider(mainCatalog);

// now set up a container with mocks
var mockContainer = new CompositionContainer();
mockContainer.ComposeExportedValue<IFoo>(fooMock);
mockContainer.ComposeExportedValue<IBar>(barMock);

// use this testContainer, it will give precedence to mocks when available
var testContainer = new CompositionContainer(mockContainer, mainExportProvider);

// link back to the testContainer so mainExportProvider picks up the mocks
mainExportProvider.SourceProvider = testContainer;
//首先设置主导出提供程序
var mainCatalog=newaggregateCatalog(…);
var mainExportProvider=新目录导出提供程序(mainCatalog);
//现在用mock设置一个容器
var mockContainer=new CompositionContainer();
mockContainer.ComposeExportedValue(fooMock);
mockContainer.ComposeExportedValue(barMock);
//使用此testContainer,它将在可用时优先考虑模拟
var testContainer=newcompositioncontainer(mockContainer,mainExportProvider);
//链接回testContainer,以便mainExportProvider拾取模拟
mainExportProvider.SourceProvider=testContainer;

(1)从你的博客判断,我相信你已经知道这一点。但是其他人也会读到这个答案,所以我想澄清一下“单元测试”这个术语。

无法让公认的解决方案发挥作用。下面的代码应该可以工作,优先级在
AggregateExportProvider
的文档中有描述

var mainContainer = new CompostionContainer();
mainContainer.ComposeExportedValue<IFoo>(new Foo() {Test = 1});

var mockContainer = new CompositionContainer();            
mockContainer.ComposeExportedValue<IFoo>(new Foo() {Test = 2});

var aggregateExportProvider = new AggregateExportProvider(
     mockContainer,   // IFoo in this container takes precedence
     mainContainer);

IFoo foo = aggregateExportProvider.GetExportedValue<IFoo>();

Console.WriteLine(foo.Test); // Outputs: 2
var mainContainer=new CompostionContainer();
mainContainer.ComposeExportedValue(新的Foo(){Test=1});
var mockContainer=new CompositionContainer();
mockContainer.ComposeExportedValue(新的Foo(){Test=2});
var aggregateExportProvider=新的aggregateExportProvider(
mockContainer,//此容器中的IFoo优先
主容器);
IFoo foo=aggregateExportProvider.GetExportedValue();
Console.WriteLine(foo.Test);//产出:2

这起作用但没有解决我的问题-
GetExportedValue
现在返回模拟。但是,创建导入IRole的对象仍然使用实际实现。e、 g.
testContainer.GetExportedValue仍然使用实际实现。与“单元测试”点相关,是的,我使用了错误的单词。事实上,我正在用NUnit写一个验收测试。@Gishu:对不起,我是凭记忆写这个例子的,而不是看我的测试,如果我有这个功能的话。我编辑了我的答案;这个例子现在应该如您所期望的那样工作。诀窍是使用
CatalogExportProvider.SourceProvider
property.nice。它起作用了。。我花了一天时间试图找出原因——直到我读了格伦·布洛克的文章。