我正在尝试让MEF重新组合它在更新导出的实例时所知道的所有部分。基本上我想让MEF更新所有在更改时导入连接字符串配置值的部分。一切看起来都很好,直到我想要更改实例。如果我尝试使用更新后的值ComposeParts,它似乎将第二个部分实例添加到容器中,然后我的导入会更新,但是为null。
有谁可以指出我哪里出错了?或者我应该尝试以这种方式使用MEF?
我正在使用MEF预览9并且目标是.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; }
}
}
答案 0 :(得分:6)
对于您要完成的方案,您有一些小事情。
首先:如果要添加/删除/更改特定导出,则它必须不在目录本身中,因此您应该删除具有“导出设置”属性的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; }
}