MEF如何获取非共享实例引用

MEF how to get non-shared instance references

最近,我在 WPF 应用程序中使用 MEF 时遇到问题。我创建了几个 class 如下所示。 Part 类型设置为 CreationPolicy.NonShared,这样将有 2 个不同的对象导入到 ClassA 和 ClassB。

[Export]
[PartCreationPolicy(CreationPolicy.NonShared)]
public class Part
{
    public int Id { get; set; }
}

[Export]
public class ClassA
{
    [Import]
    public Part PartA { get; set; }
}

[Export]
public class ClassB
{
    [Import]
    public Part PartB { get; set; }
}

我在下面写了一小段代码来描述我的问题。

[Export]
class Program
{
    [Import]
    public ClassA A { get; set; }

    [Import]
    public ClassB B { get; set; }

    [ImportMany(AllowRecomposition = true)]
    public IEnumerable<Part> AllParts { get; set; }

    static void Main(string[] args)
    {
        var catalog = new AssemblyCatalog(typeof(Program).Assembly);
        var container = new CompositionContainer(catalog);

        var prog = container.GetExportedValue<Program>();

        foreach (var part in prog.AllParts)
        {
            // Do something for Part instances.
            // I want to get all Part instances created by MEF which have imported to ClassA and ClassB.
            // However, it comes a list with a brand new Part instance.
        }
    }
}

因此将有ClassA、ClassB 和导入到Program 对象的Part 实例列表。实际上,我想得到的是 MEF 容器创建的所有 Part 实例。但是,它带有一个带有全新 Part 实例的列表。

我理解可能是因为 CreationPolicy.NonShared 我指定为 Part class。但即使我试图在 container.Catalog.Parts 中找到它们,我也只在其中找到一个 Part 实例。这让我很困惑。根据我的理解,容器应该包含它创建的对象的所有引用,因为我已经指定了 AllowRecomposition = true。我找到了一个 article 来证明这一点。它说:

Container and parts references

We believe that .Net Garbage Collector is the best thing to rely on for proper clean up. However, we also need to provider a container that has a deterministic behavior. Thus, the container will not hold references to parts it creates unless one of the following is true:

  • The part is marked as Shared
  • The part implements IDisposable
  • One or more imports is configured to allow recomposition

For those cases, a part reference is kept. Combined with the fact that you can have non shared parts and keep requesting those from the container then memory demand can quickly become an issue. In order to mitigate this issue you should rely on one of the following strategies discussed in the next two topics.

所以我有两个问题:

  1. 为什么我在容器中找不到超过一个 Part 类型的实例?

  2. 如何在我的演示中获取所有导出的 Part 实例?

ImportMany 并不像你想的那样。

考虑以下因素:

public interface IMyInterface
{
    int Id { get; }
}

[Export(typeof(IMyInterface))]
[PartCreationPolicy(CreationPolicy.NonShared)]
public class Part1 : IMyInterface
{
    public int Id { get; private set; }
}

[Export(typeof(IMyInterface))]
[PartCreationPolicy(CreationPolicy.NonShared)]
public class Part2 : IMyInterface
{
    public int Id { get; private set; }
}

[Export]
public class ClassA
{
    [ImportMany]
    public IEnumerable<IMyInterface> Parts { get; set; }
}

class Program
{
    static void Main(string[] args)
    {
        var catalog = new AssemblyCatalog(typeof(Program).Assembly);
        var container = new CompositionContainer(catalog);

        var a = container.GetExportedValue<ClassA>();
        // ...
    }
}

此时,a.Parts 属性 将包含两个实例:一个 Part1 和一个 Part2.

所以目的ImportMany不是让你获取所有之前导出的实例,而是获取每个导出接口的新实例。

至于你的问题 如何获取所有导出的 non-shared 实例,我认为这是不可能的,因为这就是它的全部意义所在non-shared.