4

MVVM アプリケーションで MEF (.NET 4、現時点では 4.5 を使用できません) を使用しています。たとえばテーブルの編集可能な行など、その場でモデルを作成する必要があるまでは、すべて問題ありませんでした。私はメモリ リークに遭遇したくなかったので、この記事http://pglazkov.blogspot.ch/2011/04/mvvm-with-mef-viewmodelfactory.htmlを見つけ、理解したい予期しない動作を発見しました。 . これは、Shell.Items オブザーバブル コレクションに追加されたアイテムです。

[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;
        }
    }

    [..]
}

このコードを使用すると、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 メソッドを使用するのが危険かどうか (私はアプリケーションの他の部分でそのメソッドを使用しています)、および有効期間が短いビュー モデルでメモリ リークを回避するためのベスト プラクティスはどれかを理解したいと思います。

どんな助けでも大歓迎

4

1 に答える 1

9

私の知る限り(MEFのソースコードを実験して見ることから):

  1. コンテナーが破棄されると、破棄可能なすべてのエクスポートされたカタログ パーツも破棄されます。エクスポートされたカタログ パーツは、ExportAttribute で装飾されているか、RegistrationBuilder (MEF2) を使用してエクスポートとして指定されているパーツです。これらのパーツはコンテナーによって作成され、その寿命はコンテナー自体の寿命に依存します。
  2. 一方、CompositionContainer.SatisfyImportsOnceまたはCompositionContainer.ComposePartsを使用して手動で作成および構成されたオブジェクトは破棄されません。それらの寿命は、コンテナーの寿命に依存しません。

GetExportedValue と SatisfyImports の違いは同じではありません。GetExportedValue は、コンテナーに登録されているすべてのエクスポートされたパーツを返します。これには、コンテナーによって作成されたパーツ (1. で説明したエクスポートされたカタログ パーツ) と、CompositionContainer.ComposeParts を使用して登録されたパーツが含まれます。SatisfyImports は、利用可能なすべてのインポートを注入しますが、そのクラスがエクスポートされた型としてマークされていても、オブジェクトをエクスポートとして登録しません (1. を参照)。さらに、SatisfyImports は再構成を無効にしますが、これはトピックから外れています。

CodePlex に関する MEF のドキュメントは、パーツの有効期間に関する貴重な情報を提供します。

于 2013-08-20T09:07:46.387 に答える