代码之家  ›  专栏  ›  技术社区  ›  Matt

当我更改部件时,如何让MEF重新编译?

  •  5
  • Matt  · 技术社区  · 14 年前

    我试图让MEF重新编译它在更新导出的实例时知道的所有部分。本质上,我希望MEF在更改连接字符串配置值时更新导入该值的所有部分。在我想更改实例的地方,一切都看起来很好。如果我尝试用更新的值组合部件,它似乎会向容器中添加第二个部件实例,然后我的导入将被更新,但为空。

    有人能指出我哪里出错了吗?或者我应该尝试用这种方式来使用MEF吗?

    我正在使用MEF Preview 9和Targetting.NET Framework 3.5以及WPF。

    using System;
    using System.Collections.Generic;
    using System.ComponentModel.Composition;
    using System.ComponentModel.Composition.Hosting;
    using System.Linq;
    using System.Text;
    using Shouldly;
    
    namespace ConsoleApplication4
    {
        class Program
        {
            static void Main(string[] args)
            {
                MainClass main = new MainClass();
                main.RunTest();
            }
        }
    
        public class MainClass
        {
            [ImportMany]
            public IEnumerable<Settings> Settings { get; set; }
    
            public void RunTest()
            {
                AggregateCatalog catalog = new AggregateCatalog();
                catalog.Catalogs.Add(new AssemblyCatalog(typeof(Settings).Assembly));
    
                CompositionContainer container = new CompositionContainer(catalog);
    
                container.SatisfyImportsOnce(this);
    
                Config cfg = new Config
                {
                    Settings = new Settings { ConnectionString = "Value1" },
                };
    
                // result is returned with a null settings value
                UsesSettings result = container.GetExportedValue<UsesSettings>();
    
                // this recomposes everything with the new value, result changes to have settings of Value1
                container.ComposeParts(cfg);
    
                // this line results in my import many enumerable returning 2 parts the Value1 setting and null
                container.SatisfyImportsOnce(this);
    
                result.TheSettings.ConnectionString.ShouldBe("Value1");
    
                cfg.Settings = new Settings { ConnectionString = "Value2" };
    
                // how do I tell the container to recompose now I have changed the config object,
                // or how do I replace the part value with the new value?
    
                // this line causes the result.Settings to return null
                container.ComposeParts(cfg);
    
                // this updates the ImportMany to 3 values, Value1, Value2 and null
                container.SatisfyImportsOnce(this);
            }
        }
    
        public class Settings
        {
            public string ConnectionString = "default value";
        }
    
        public class Config
        {
            [Export(typeof(Settings))]
            public Settings Settings { get; set; }
        }
    
        [Export(typeof(UsesSettings))]
        public class UsesSettings
        {
            [Import(typeof(Settings), AllowRecomposition = true)]
            public Settings TheSettings { get; set; }
        }
    }
    
    1 回复  |  直到 14 年前
        1
  •  6
  •   Wes Haggard    14 年前

    对于您要完成的场景,您有一些事情要做。

    首先:如果要添加/删除/更改特定的导出,则该导出不能位于目录本身,因此应删除具有导出设置属性的配置类。这是由CatalogExportProvider创建的,也是您在集合中看到空值的原因。

    请尝试以下操作:

    public class Program
    {
        [ImportMany(AllowRecomposition=true)]
        public IEnumerable<Settings> Settings { get; set; }
    
        public void RunTest()
        {
            AggregateCatalog catalog = new AggregateCatalog();
            catalog.Catalogs.Add(new AssemblyCatalog(typeof(Settings).Assembly));
    
            CompositionContainer container = new CompositionContainer(catalog);
    
            // Settings should have 0 values.
            container.ComposeParts(this);
            Contract.Assert(this.Settings.Count() == 0);
    
            CompositionBatch batch = new CompositionBatch();
    
            // Store the settingsPart for later removal...
            ComposablePart settingsPart = 
                batch.AddExportedValue(new Settings { ConnectionString = "Value1" });
    
            container.Compose(batch);
    
            // Settings should have "Value1"
            UsesSettings result = container.GetExportedValue<UsesSettings>();
            Contract.Assert(result.TheSettings.ConnectionString == "Value1");
    
            // Settings should have 1 value which is "Value1";
            Contract.Assert(this.Settings.Count() == 1);
            Contract.Assert(this.Settings.First().ConnectionString == "Value1");
    
            // Remove the old settings and replace it with a new one.
            batch = new CompositionBatch();
            batch.RemovePart(settingsPart);
            batch.AddExportedValue(new Settings { ConnectionString = "Value2" });
            container.Compose(batch);
    
            // result.Settings should have "Value2" now.
            Contract.Assert(result.TheSettings.ConnectionString == "Value2");
    
            // Settings should have 1 value which is "Value2"
            Contract.Assert(this.Settings.Count() == 1);
            Contract.Assert(this.Settings.First().ConnectionString == "Value2");
        }
    }
    public class Settings
    {
        public string ConnectionString = "default value";
    }
    
    [Export(typeof(UsesSettings))]
    public class UsesSettings
    {
        [Import(typeof(Settings), AllowRecomposition = true)]
        public Settings TheSettings { get; set; }
    }