MEF:GetExportedValue和SatisfyImports之间的区别

时间:2013-08-19 13:20:43

标签: c# .net .net-4.0 memory-leaks mef

我们在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;
        }
    }

    [..]
}

如果我使用此代码,则该项目与子容器一起处理。 如果我将其更改为:

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方法是否有危险(我在应用程序的其他部分使用该方法),这是避免内存泄漏的最佳做法,对于寿命较短的视图模型。

任何帮助表示赞赏

1 个答案:

答案 0 :(得分:7)

据我所知(通过试验和观察MEF的source code):

  1. 当放置容器时,所有出口的一次性目录部件也被丢弃。导出的目录部件是使用ExportAttribute修饰或使用RegistrationBuilder(MEF2)指定为导出的部件。这些部件由容器创建,其使用寿命取决于容器本身的使用寿命。
  2. 另一方面,不会处理使用CompositionContainer.SatisfyImportsOnceCompositionContainer.ComposeParts手动创建和撰写的对象。它们的寿命不依赖于容器的寿命。
  3. 现在,GetExportedValue和SatisfyImports之间的区别并不相同。 GetExportedValue返回向容器注册的所有导出部件。这包括容器创建的部件(1.中提到的导出目录部件)以及使用CompositionContainer.ComposeParts注册的部件。 SatisfyImports将注入任何可用的导入,但不会将该对象注册为导出,即使其类被标记为导出类型(请参阅1.)。此外,SatisfyImports将禁用重构,但这不是主题。

    MEF关于CodePlex的文档提供了有关Parts Lifetime的重要信息。