繁体   English   中英

如何交换/替换MEF容器中的共享(单个)对象?

[英]How to exchange/replace the shared (singleton) object in MEF container?

这可能很简单,但是由于我是MEF领域的新手,所以我很难找出解决问题的方法。

我正在使用WPF + Prism和MEF作为DI容器的应用程序。 我想通过将对象(例如RuleFile )与文件关联来将我的对象(即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导出的对象吗?

您不必替换MEF容器中的实例,那不是它的工作方式,这是危险的并且完全无法管理。 (还请记住,C#不是C,您可以在其中简单地更改指向的对象)。 假设一个类X从容器中获取一个实例,并具有一个工厂方法,在该方法中该类将另一个实例Y传递给该实例。现在突然您想“替换”该实例。 首先,旧实例将要发生什么? 配置? 还活着吗? 邮寄给您的祖母? 其次,如果X使用GetExportedValue了实例,那么您将如何通知它实例已经消失并被其他对象替换? 您不能..第三,假设X使用Import代替,并且由于某种魔力,它被通知其实例已被替换。 现在又该如何通知Y该实例已被替换? 除非您保留Y.等等等的列表,否则您不能。我希望这样可以清楚地替换容器中的对象不是一个好主意。

不过,您可以做两件事:

  1. 只要确保将RuleFile创建并注入到容器中,然后再将其导入任何地方。 这也很有意义:我给RuleFile印象是某种应用程序范围的配置,因此希望在应用程序启动之前就已完全设置此配置。 重写MefBootstrapper.ConfigureContainer ,反序列化RuleFile实例,并使用ComposeExportedValue将其设置为容器中的唯一实例。 如果反序列化失败,则显示错误对话框并中止您的应用程序,或者提供默认配置并注入该配置。

  2. 提供对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" ) 

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM