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

时间:2017-01-12 05:40:21

标签: .net wpf prism mef

最近,我在WPF应用程序中使用MEF时遇到了问题。我创建了几个类,如下所示。 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 intances列表。实际上,我想要得到的是MEF容器创建的所有Part部分。但是,它带有一个全新的Part实例列表。

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

  

容器和零件参考

     

我们相信.Net垃圾收集器是最好的依赖   适当的清理。但是,我们还需要提供具有确定性行为的容器。因此,除非满足下列条件之一,否则容器将不会保留对其创建的零件的引用:

     
      
  • 该部件标记为共享
  •   
  • 该部分实现IDisposable
  •   
  • 配置一个或多个导入以允许重新组合
  •   
     

对于这些情况,保留零件参考。结合您可以拥有非共享部分并继续从容器中请求这些部分这一事实,内存需求可能很快成为问题。为了缓解此问题,您应该依赖以下两个主题中讨论的以下策略之一。

所以我有两个问题:

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

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

1 个答案:

答案 0 :(得分:1)

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不是为了获取所有以前导出的实例,而是为了获取导出界面的每个导出的新实例。

关于如何获取所有导出的非共享实例的问题,我不相信这是可能的,因为这是非共享