2013-08-19 33 views
4

我們在MVVM應用程序中使用MEF(.NET 4,目前無法使用4.5)。 一切都很好,直到我們需要即時創建模型,例如表的可編輯行。 我不想遇到內存泄漏,我發現這篇文章http://pglazkov.blogspot.ch/2011/04/mvvm-with-mef-viewmodelfactory.html,我發現了一個我想要理解的意外行爲。 這是一個項目添加到Shell.Items觀察到的集合:MEF:GetExportedValue和SatisfyImports之間的區別

[PartCreationPolicy(CreationPolicy.NonShared)] 
[Export] 
public class Item : INotifyPropertyChanged, IDisposable 
{ 
    [Import] 
    private Lazy<Shell> shell; 

    /// <summary> 
    /// Initializes a new instance of the <see cref="Item"/> class. 
    /// </summary> 
    public Item() 
    { 
     this.Time = DateTime.Now; 
    } 

    ~Item() 
    { 
     this.Dispose(false); 
    } 

    public event PropertyChangedEventHandler PropertyChanged; 

    public Shell Shell 
    { 
     get 
     { 
      return this.shell.Value; 
     } 
    } 

    public DateTime Time { get; private set; } 

    public void Initialize() 
    { 
     this.Shell.ItemsCount++; 
    } 

    public void Dispose() 
    { 
     this.Dispose(true); 
    } 

    private void Dispose(bool disposing) 
    { 
     if (disposing) 
     { 
      this.Shell.ItemsCount--; 
     } 
    } 

    [..] 
} 

這是工廠:

[PartCreationPolicy(CreationPolicy.Shared)] 
[Export] 
public class ChildContainerItemFactory : ItemFactory 
{ 
    public override Item Create() 
    { 
     var container = ServiceLocator.Current.GetInstance<CompositionContainer>(); 
     using (var childContainer = CreateTemporaryDisposableContainer(container)) 
     { 
      var item = childContainer.GetExportedValue<Item>(); 
      item.Initialize(); 
      return item; 
     } 
    } 

    [..] 
} 

如果我用這個代碼,該項目是與孩子一起容器配置。 如果我將其更改爲:

public override Item Create() 
    { 
     var container = ServiceLocator.Current.GetInstance<CompositionContainer>(); 
     using (var childContainer = CreateTemporaryDisposableContainer(container)) 
     { 
      var item = new Item(); 
      childContainer.SatisfyImportsOnce(item); 
      item.Initialize(); 
      return item; 
     } 
    } 

該項目是不再與容器配置。 我想了解使用GetExportedValue方法(我在應用程序的其他部分使用該方法)是否危險,以及哪種避免內存泄漏的最佳做法是使用壽命較短的視圖模型。

任何幫助表示讚賞

回答

7

據我所知(從實驗和觀察MEF的source code):

  1. 當容器被佈置,這是一次性的所有導出目錄的部分也被佈置。導出的目錄部分是使用ExportAttribute裝飾的目錄部分,或使用RegistrationBuilder(MEF2)指定爲導出目錄的部分。這些零件是由容器創建的,它們的壽命取決於容器本身的壽命。
  2. 另一方面,使用CompositionContainer.SatisfyImportsOnceCompositionContainer.ComposeParts手動創建和組合的對象不會被丟棄。它們的壽命不依賴於容器的壽命。

現在GetExportedValue和SatisfyImports之間的區別是不一樣的。 GetExportedValue返回在容器中註冊的所有導出零件。這包括由容器創建的零件(在1中提到的導出目錄零件)以及使用CompositionContainer.ComposeParts註冊的零件。 SatisfyImports將注入任何可用的導入,但不會將該對象註冊爲導出,即使其類已標記爲導出類型(請參閱1.)。此外,SatisfyImports將禁用重新組合,但這不是主題。

MEF關於CodePlex的文檔提供了關於Parts Lifetime的寶貴信息。