这可能很简单,但由于我是MEF领域的新手,这就是为什么我难以找到解决问题的方法。
我正在使用WPF + Prism和MEF作为DI容器的应用程序。我想通过将其与文件说法RuleFile1.ruleapp相关联来将我的对象(即RuleFile
)与每个应用程序实例联系起来。因此,我使用属性[PartCreationPolicy(CreationPolicy.Shared)]
对其进行了修饰,将其视为单例,以便它在整个应用程序中与每个应用程序实例保持相同。
[Serializable()]
[Export]
[PartCreationPolicy(CreationPolicy.Shared)]
public class RuleFile : NotifyPropertyChanged, IRuleFile { }
接下来,在ViewModel [ImportingContructor]
时,如下所示,对象与所需的相同。
[ImportingConstructor]
public RuleViewModel(RuleFile ruleFile)
[ImportingConstructor]
public SchemaViewModel(RuleFile ruleFile)
直到现在一切都很顺利。
使用下面的代码,我试图获得传递给视图模型的相同导出对象,如上所述,但container.GetExportedValue<IRuleFile>()
正在提供一个不同的新对象引用:
var catalog = new AssemblyCatalog(System.Reflection.Assembly.GetExecutingAssembly());
var container = new CompositionContainer(catalog);
var exportObj = container.GetExportedValue<IRuleFile>();
问题1:为什么我会得到不同的引用,尽管对象应该与CreationPolicy.Shared
的单例对象相同?
问题2:最终,所有努力都是用MEF DI容器中的反序列化对象交换/替换RuleFile
导出的对象?
答案 0 :(得分:1)
您不会替换MEF容器中的实例,这不是它的工作方式,而且它是危险的并且完全无法管理。 (还要记住C#不是C,你可以简单地改变指向对象)。假设一个类X从容器中获取一个实例并且有一个工厂方法,在该方法中它将该实例传递给另一个类Y.现在突然想要“替换”该实例。首先,旧实例会发生什么?配置?活着?邮寄给你的祖母?其次,如果X使用GetExportedValue
获取实例,您将如何通知它它已经消失的实例并被其他内容替换?你不能......第三,假设X使用了Import
代替了一些魔法,它会被告知它的实例已被替换。现在又如何通知Y实例被替换?你不能,除非你保留Y.等等的清单,我希望这清楚地说明更换容器中的对象并不是一个好主意。
但是你可以做几件事:
只需确保创建RuleFile并将其注入容器,然后再将其导入。这也是最有意义的:我的印象是RuleFile是某种应用程序范围的配置,因此希望在应用程序启动之前完全设置此配置。覆盖MefBootstrapper.ConfigureContainer
,反序列化RuleFile实例并使用ComposeExportedValue
将其设置为容器中的唯一实例。如果反序列化失败,您将显示错误对话框并中止您的应用程序,或者提供默认配置并将其注入。
提供RuleFile的包装器,如果可用,则从反序列化的RuleFile读取,或者提供默认值。因此,观察到的行为与在容器中替换的RuleFile相同。但是,这有一个主要的缺点,如果在加载文件之前有使用IRuleFile实例的代码,它会获得与加载文件后不同的值。这就是为什么第一种方法更好的原因。例如:
private class DefaultRuleFile: IRulefile
{
string SomeProperty
{
get{ return "DefaultValue"; }
}
}
[Export( typeof( IRulefile ) )]
[Export( typeof( RuleFileImplementation ) )]
[PartCreationPolicy(CreationPolicy.Shared)]
public class RuleFileImplementation : IRulefile
{
private IRuleFile impl;
RuleFileImplementation()
{
impl = new DefaultRuleFile();
}
string SomeProperty
{
get{ return impl.SomeProperty; }
}
void LoadFromFile( string file )
{
impl = SerializationHelper.Deserialize<IRuleFile>( file );
}
}
//at some point in the application:
container.GetExportedValue<RuleFileImplementation>().LoadFromFile( "file" )