我正在试验MEF并创建了一个测试程序来调用实现某些给定接口的“插件”,如下所示:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace ProbeContract
{
public interface IProbe
{
int DoProbe(string what);
List<string> GetCapabilities();
}
}
我创建了一个示例控制台程序,它从它自己的程序集中加载“插件”,如果找到的话,从一个放置额外 DLL 的目录中加载。无论插件目录为空(仅调用“本机”插件)还是具有兼容的 DLL,程序都可以正常工作。但是...如果在循环迭代之间添加了一个新的 DLL,DirectoryCatalog 的 Refresh() 方法会抛出一个 ChangeRejectedException,解释如下:
组成保持不变。由于以下错误,更改被拒绝: 合成产生了单个合成错误。下面提供了根本原因。查看 CompositionException.Errors 属性以获取更多详细信息。
1) 部分 'MEFTest.Program' 上的不可重组导入 'MEFTest.Program.ProberSet (ContractName="ProbeContract.IProbe")' 阻止了出口的变化。
该程序如下,后面是我尝试添加的 DLL 的代码。我究竟做错了什么?
using System;
using System.IO;
using System.Reflection;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using ProbeContract;
using System.ComponentModel.Composition;
using System.ComponentModel.Composition.Hosting;
namespace MEFTest
{
class Program
{
[ImportMany]
IEnumerable<IProbe> ProberSet { get; set; }
CompositionContainer exportContainer;
DirectoryCatalog pluginCatalog;
AggregateCatalog catalog;
private void Run()
{
catalog = new AggregateCatalog();
catalog.Catalogs.Add(new AssemblyCatalog(Assembly.GetExecutingAssembly()));
string myExecName = Assembly.GetExecutingAssembly().Location;
string myPath = Path.GetDirectoryName(myExecName);
pluginCatalog = new DirectoryCatalog(myPath + "/Plugins");
catalog.Catalogs.Add(pluginCatalog);
exportContainer = new CompositionContainer(catalog);
CompositionBatch compBatch = new CompositionBatch();
compBatch.AddPart(this);
compBatch.AddPart(catalog);
exportContainer.Compose(compBatch);
for (; ; )
{
Console.Write("Press any key to run all probes: ");
Console.ReadKey(true);
Console.WriteLine();
pluginCatalog.Refresh();
foreach (var Prober in ProberSet)
{
Prober.DoProbe("gizmo");
}
}
}
static void Main(string[] args)
{
Program p = new Program();
p.Run();
}
}
}
插件。其他两个插件类似,唯一的区别是它们与主程序位于同一个程序集中:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.ComponentModel.Composition;
using ProbeContract;
namespace OtherProbes
{
[Export(typeof(IProbe))]
public class SpankyNewProber : IProbe
{
public int DoProbe(string what)
{
Console.WriteLine("I'm Spanky and New and I'm probing [{0}]", what);
return 0;
}
public List<string> GetCapabilities()
{
List<string> retVal = new List<string>();
retVal.Add("spanky");
retVal.Add("new");
return retVal;
}
}
}