C# 如果在目录中找到新DLL,则对DirectoryCatalog调用Refresh()会引发ChangeRejectedException

C# 如果在目录中找到新DLL,则对DirectoryCatalog调用Refresh()会引发ChangeRejectedException,c#,mef,composition,C#,Mef,Composition,我正在试验并创建一个测试程序来调用实现某些给定接口的“插件”,如下所示: using System; using System.Collections.Generic; using System.Linq; using System.Text; namespace ProbeContract { public interface IProbe { int DoProbe(string what); List<string> GetCa

我正在试验并创建一个测试程序来调用实现某些给定接口的“插件”,如下所示:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace ProbeContract
{
    public interface IProbe
    {
        int DoProbe(string what);
        List<string> GetCapabilities();
    }
}
使用系统;
使用System.Collections.Generic;
使用System.Linq;
使用系统文本;
命名空间ProbeContract
{
公共接口IProbe
{
int DoProbe(字符串what);
列出GetCapabilities();
}
}
我创建了一个示例控制台程序,该程序从自己的程序集加载“插件”,如果找到了,则从一个目录加载“插件”,在该目录中放置额外的DLL。无论插件目录是空的(只调用“本机”插件),还是从兼容的DLL开始,程序都可以正常工作。但是如果在循环迭代之间添加新的DLL,DirectoryCatalog的Refresh()方法将抛出ChangeRejectedException,如下所述:

组成保持不变。这个 更改被拒绝,因为 以下错误:合成错误 产生了一个构图错误。 下面提供了根本原因。 查看CompositionException.Errors 属性以获取更多详细信息 信息

1) 防止出口变化 不可重组导入 'MEFTest.Program.ProberSet (ContractName=“ProbeContract.IProbe”)' 在“MEFTest.Program”部分

下面是程序,后面是我尝试添加的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();
        }
    }
}
使用系统;
使用System.IO;
运用系统反思;
使用系统集合;
使用System.Collections.Generic;
使用System.Linq;
使用系统文本;
使用ProbeContract;
使用System.ComponentModel.Composition;
使用System.ComponentModel.Composition.Hosting;
名称空间MEFTest
{
班级计划
{
[进口数量]
IEnumerable ProberSet{get;set;}
复合容器出口容器;
目录插件目录;
AggregateCatalog目录;
私家车
{
catalog=新的AggregateCatalog();
catalog.Catalogs.Add(新的AssemblyCatalog(Assembly.getExecutionGassembly());
字符串myExecName=Assembly.GetExecutionGassembly().Location;
字符串myPath=Path.GetDirectoryName(myExecName);
pluginCatalog=newdirectorycatalog(myPath+“/Plugins”);
catalog.Catalogs.Add(pluginCatalog);
exportContainer=新的合成容器(目录);
CompositionBatch compBatch=新的CompositionBatch();
compBatch.AddPart(本);
compBatch.AddPart(目录);
exportContainer.Compose(compBatch);
对于(;;)
{
编写(“按任意键运行所有探测:”);
Console.ReadKey(true);
Console.WriteLine();
pluginCatalog.Refresh();
foreach(ProberSet中的var Prober)
{
探测装置(“gizmo”);
}
}
}
静态void Main(字符串[]参数)
{
程序p=新程序();
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;
        }
    }
}
使用系统;
使用System.Collections.Generic;
使用System.Linq;
使用系统文本;
使用System.ComponentModel.Composition;
使用ProbeContract;
命名空间其他探测
{
[导出(类型(IProbe))]
公共类SpankyNewProber:IProbe
{
公共int DoProbe(字符串what)
{
WriteLine(“我是新来的,我在探索[{0}]”,什么);
返回0;
}
公共列表GetCapabilities()
{
List retVal=新列表();
返回。添加(“spanky”);
检索添加(“新”);
返回返回;
}
}
}

我假设您使用的是MEF preview 6,因为您会看到拒绝异常。您看到更改被拒绝的原因是您的ProberSet不可重新编译。尝试将ProberSet导入更改为:

[ImportMany(AllowRecomposition=true)]        
IEnumerable<IProbe> ProberSet { get; set; }
[ImportMany(AllowRecomposition=true)]
IEnumerable ProberSet{get;set;}
这样做将允许在完成此导入后将新的IProbe导出引入目录/容器

这里的想法是,一旦您获得稳定的组合,我们将拒绝任何可能破坏该组合的更改,并且在您的情况下,您声明您需要一组不可重新编译的IProbe对象,因此在初始设置后添加新的IProbe将违反该要求