8

我正在试验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;
        }
    }
}
4

1 回答 1

13

我假设您使用的是 MEF 预览版 6,因为您看到了拒绝异常。您看到更改被拒绝的原因是您的 ProberSet 不可重组。尝试将 ProberSet 导入更改为:

[ImportMany(AllowRecomposition=true)]        
IEnumerable<IProbe> ProberSet { get; set; }

这样做将允许在此导入已组合后将新的 IProbe 导出引入到目录/容器中。

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

于 2009-07-16T01:07:55.580 回答