为什么在MEF中使用Import和GetExportedValue对共享对象进行不同的对象引用?

时间:2014-09-01 06:11:04

标签: c# prism mef prism-5

我有一个如下所示的对象。

[Serializable()]
[Export(typeof(IRuleFile))]    
[PartCreationPolicy(CreationPolicy.Shared)]
public class RuleFile : NotifyPropertyChanged, IRuleFile { }

使用[ImportConstructor][Import],返回相同的对象引用。

但是通过使用编程方法,返回的对象是不同的,尽管它应该是单例,为什么?

var catalog = new AssemblyCatalog(System.Reflection.Assembly.GetExecutingAssembly());
var container = new CompositionContainer(catalog);
var exportedObj = container.GetExportedValue<IRuleFile>();

ADDED

我的解决方案中有两个视图模型,下面我只显示一个,但[ImportConstructor]对象保持相同但使用GetExportedValue时我得到一个新实例,构造函数再次调用。

[Export]
[PartCreationPolicy(CreationPolicy.Shared)]
public partial class RuleViewModel : ViewModelBase
{
    [ImportingConstructor]
    public RuleViewModel(IRuleFile ruleFile)
    {
        RuleFile = ruleFile; // here the object is fine            
    }

    // this method triggers at the time of loading rule file
    public void LoadRuleState()
    {
        var catalog = new AssemblyCatalog(System.Reflection.Assembly.GetExecutingAssembly());
        var container = new CompositionContainer(catalog);
        // at this point contructor triggers again in my case
        var exportedObj = container.GetExportedValue<IRuleFile>(); 

        // my intend is to replace the object back in the container after deserialization.
        RuleFile = SerializationHelper.DeserializeFromFile<RuleFile>(Constants.RuleDefinitionPath);
        container.ComposeExportedValue<IRuleFile>(RuleFile);
    }
}

我的实际意图是在反序列化后将对象替换回MEF容器中,以便对象保持不变。

1 个答案:

答案 0 :(得分:1)

创建两个实例的原因是您的代码使用了两个不同的AssemblyCatalogCompositionContainer个实例,而这些实例完全独立。因此,当使用Import等等时,MEF使用在引导程序中创建的全局容器实例。但是在LoadRuleState中,您创建了一个新容器,该容器为空,并且不知道任何对象的现有实例,因此在您请求它时会创建一个新的RuleFile。

当你想在引导程序之外使用CompositionContainer时,通常的技巧就是简单地将它添加到自身:

public class MefMuiBootstrapper : MefBootstrapper
{
  protected override void ConfigureContainer()
  {
    base.ConfigureContainer();
    Container.ComposeExportedValue( Container );
  }
}

然后您可以像任何其他导出一样导入它:

[Export]
public class ViewModel
{
  private readonly CompositionContainer container;

  [ImportingConstructor]
  public ViewModel( CompositionContainer container )
  {
    this.container = container;
  }

  public void Load()
  {
    var exportedObj = container.GetExportedValue<IRuleFile>();
  }
}