C# 当我更改零件时,如何让MEF重新组合?

C# 当我更改零件时,如何让MEF重新组合?,c#,.net,mef,C#,.net,Mef,我试图让MEF在更新导出的实例时重新组合它知道的所有部分。本质上,我想让MEF更新所有在更改连接字符串配置值时导入连接字符串配置值的部件。在我想要更改实例之前,一切看起来都很好。如果我尝试使用更新的值组合部件,它似乎会将第二个部件实例添加到容器中,然后我的导入会被更新,但为null 有人能指出我哪里出了问题吗?或者我应该尝试以这种方式使用MEF吗 我使用的是MEF preview 9,目标是.NETFramework 3.5和WPF using System; using System.Coll

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

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

我使用的是MEF preview 9,目标是.NETFramework 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; }
    }
}
使用系统;
使用System.Collections.Generic;
使用System.ComponentModel.Composition;
使用System.ComponentModel.Composition.Hosting;
使用System.Linq;
使用系统文本;
合理使用;
命名空间控制台应用程序4
{
班级计划
{
静态void Main(字符串[]参数)
{
MainClass main=新的MainClass();
main.RunTest();
}
}
公共类主类
{
[进口数量]
公共IEnumerable设置{get;set;}
公共无效运行测试()
{
AggregateCatalog catalog=新的AggregateCatalog();
catalog.Catalogs.Add(新的AssemblyCatalog(typeof(Settings.Assembly));
CompositionContainer=新的CompositionContainer(目录);
集装箱。满足进口(本);
Config cfg=新配置
{
设置=新设置{ConnectionString=“Value1”},
};
//返回的结果带有空设置值
UseSettings result=container.GetExportedValue();
//这将使用新值重新组合所有内容,结果更改为设置值1
集装箱组件(cfg);
//这一行导致我的import many enumerable返回两个部分:Value1设置和null
集装箱。满足进口(本);
结果。设置。连接字符串应为(“值1”);
cfg.Settings=新设置{ConnectionString=“Value2”};
//我如何告诉容器重新组合现在我已经更改了配置对象,
//或者如何用新值替换零件值?
//此行导致result.Settings返回null
集装箱组件(cfg);
//这会将ImportMany更新为3个值:Value1、Value2和null
集装箱。满足进口(本);
}
}
公共类设置
{
公共字符串ConnectionString=“默认值”;
}
公共类配置
{
[导出(类型(设置))]
公共设置{get;set;}
}
[导出(类型(使用设置))]
公共类使用设置
{
[导入(类型(设置),AllowRecomposition=true)]
公共设置设置设置{get;set;}
}
}

对于您试图完成的场景,您还有一些事情需要做

第一:如果要添加/删除/更改特定导出,它不能位于目录本身中,因此应该删除具有export settings属性的Config类。这是由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; }
}
公共类程序
{
[进口数量(AllowRecomposition=true)]
公共IEnumerable设置{get;set;}
公共无效运行测试()
{
AggregateCatalog catalog=新的AggregateCatalog();
catalog.Catalogs.Add(新的AssemblyCatalog(typeof(Settings.Assembly));
CompositionContainer=新的CompositionContainer(目录);
//设置应具有0个值。
容器。组件(本);
Contract.Assert(this.Settings.Count()==0);
CompositionBatch=新的CompositionBatch();
//存储设置Spart以备以后删除。。。
组件部件设置Spart=
AddExportedValue(新设置{ConnectionString=“Value1”});
容器。组成(批);
//设置应具有“值1”
UseSettings result=container.GetExportedValue();
Contract.Assert(result.TheSettings.ConnectionString==“Value1”);
//设置应具有1个值,即“值1”;
Contract.Assert(this.Settings.Count()==1);
Assert(this.Settings.First().ConnectionString==“Value1”);
//删除旧设置并用新设置替换。
批次=新的合成批次();
批量移除零件(设置Spart);
AddExportedValue(新设置{ConnectionString=“Value2”});
容器。组成(批);
//结果。设置现在应该有“Value2”。
Contract.Assert(result.TheSettings.ConnectionString==“Value2”);
//设置应具有1个值,即“值2”
Contract.Assert(this.Settings.Count()==1);
Assert(this.Settings.First().ConnectionString==“Value2”);
}
}
公共类设置
{
公共字符串ConnectionString=“默认值”;
}
[导出(类型(使用设置))]
公共类使用设置
{
[导入(类型(设置),AllowRecomposition=true)]
公共设置设置设置{get;set;}
}

谢谢,韦斯!我修改了代码,保留了可组合部分,这使我能够更新容器中的部分,而不仅仅是添加越来越多的实例,现在效果很好。