通过静态特性组合具有不同导出名称的共享零件



需求-

  1. 声明同一接口的共享导出。出口用唯一的出口名称进行标记,这样消费者就可以进口特定风味的出口
  2. 将类的公共实例注入到一组对象中,但不在多组对象之间共享公共实例[这使我使用不同的键使用共享导出-一组对象可以使用单个键来满足其共享导入需求]

这是出口类

public interface IMyExport
{
    void Display();
}
public class MyExport : IMyExport
{
    private Guid _id = Guid.NewGuid();
    public void Display()
    {
        Console.WriteLine("Instance ID = "+_id);
    }
}

下面是我如何导出类的实例

public static class ExportInitialization
{
    [Export("Type A", typeof(IMyExport)),
    Export("Type B", typeof(IMyExport))]
    public static IMyExport IceCreamExport
    {
        get
        {
            return new MyExport();
        }
    }
}

消费者可以通过以下方式导入特定实例

[Export]
public class ImporterA
{
    private readonly IMyExport _myExport;
    [ImportingConstructor]
    public ImporterA([Import("Type A")]IMyExport myExport)
    {
        _myExport = myExport;
    }
    public void Display()
    {
        _myExport.Display();
    }
}
[Export]
public class ImporterB
{
    private readonly IMyExport _myExport;
    [ImportingConstructor]
    public ImporterB([Import("Type B")]IMyExport myExport)
    {
        _myExport = myExport;
    }
    public void Display()
    {
        _myExport.Display();
    }
}
class Program
{
    [Import]
    public ImporterA ImporterA { get; set; }
    [Import]
    public ImporterB ImporterB { get; set; }
    static void Main(string[] args)
    {
        new Program().Run();
    }
    public void Run()
    {
        var container = new CompositionContainer(new AssemblyCatalog(Assembly.GetExecutingAssembly()));
        container.ComposeParts(this);
        ImporterA.Display();
        ImporterB.Display();
        Console.ReadKey();
    }
}

这曾经在.Net 4.0中运行良好,但当安装了.Net 4.5时,我得到了以下组

Instance ID = 78bba41a-0c48-44fc-ae69-f0ead96371f9
Instance ID = 78bba41a-0c48-44fc-ae69-f0ead96371f9

请注意,两个导入都返回了对象的同一实例。我是否违反了一些关于通过静态属性导出的未记录规则?

我发现从两个不同的静态属性导出特定实例可以确保返回两个不同实例。

    [Export("Type A", typeof(IMyExport))]
    public static IMyExport ExportA
    {
        get
        {
            return new MyExport();
        }
    }
    [Export("Type B", typeof(IMyExport))]
    public static IMyExport ExportB
    {
        get
        {
            return new MyExport();
        }
    }

这是令人费解的,因为在未修改的版本中,静态getter在每次get时都会创建一个新实例。不确定这是否是4.5中引入的一些C#/.Net优化的结果,或者这是否是MEF问题

这与MEF零件的使用寿命有关。

MEF属性的默认值是,组件不会说明是否每次都要获取一个新实例。

意思是:

  • ExportAttribute没有指定导出的实例是否可以共享
  • 两个ImportAttribute都没有指定是否应该共享它们的导入

MEF的默认行为是,如果不禁止它共享实例,它会的。这意味着,根据文档,.NET 4.5的行为是正确的:MyExport的实例是共享的,因为双方都没有明确禁止共享。

我认为.NET 4.0有一个错误/差异,每次都调用静态属性,这导致了您所观察到的,即非共享实例。而你正依赖于那个bug。我认为这个bug的起源是对属性的一个基本的、框架范围的期望——让一个静态属性为每个属性调用创建一个新的、语义上不同的实例是非常不寻常的。

我相信你应该:

  1. 将静态属性导出替换为静态方法导出
  2. 在导出端或导入端指定非共享的创建策略

最新更新