MEF:使用CreationPolicy.NonShared时,将不同的构造函数参数传递给零件

本文关键字:参数传递 构造函数 零件 CreationPolicy 使用 NonShared MEF | 更新日期: 2023-09-27 18:29:31

我知道关于使用MEF的构造函数参数注入有很多问题,但我的问题有点不同。

我想知道,当我使用PartCreationPolicy(CreationPolicy.NonShared)GetExportedValue的组合时,有什么方法可以将不同的参数值传递给零件的构造函数吗?

例如:

[PartCreationPolicy(CreationPolicy.NonShared)]
[Export]
public partial class Foo
{
    [ImportingConstructor]
    public Foo([Import("SomeParam")]object parameter)
    {
        ...
    }
}

在其他地方。。。

container.ComposeExportedValue("SomeParam", "Some value...");
var instance = container.GetExportedValue<Foo>();

在上面的例子中,我只能使用ComposeExportedValue一次,因为第二次运行它将导致ChangeRejectedException

所以,我的问题是:

  1. 在上述场景中,对于每个新实例,是否有其他方法可以更改SomeParam的值
  2. 如果没有,在不使用任何其他DI框架的情况下,还有什么其他方法可以实现这一点?脑海中浮现的一件事是创建一个服务来公开类似System.Collections.Concurrent.ConcurrentQueue的东西,在调用GetExportedValue之前,我将参数值排入队列,然后在部件的构造函数中出列该值。但这是一次黑客攻击,也造成了比解决问题更多的问题
  3. 如果以上两个问题的答案都是否定的,那么有没有其他方法可以通过MEF和其他DI/IOC框架来实现这一点

谢谢你的帮助。:)
此致,
Yogesh Jagota

MEF:使用CreationPolicy.NonShared时,将不同的构造函数参数传递给零件

如果以上两个问题的答案都是否定的,那么有没有其他方法可以通过MEF和其他DI/IOC框架来实现这一点?

我认为问题1和问题2的答案确实是否定的。

我会尝试AutoFac,它可以为您提供更细粒度的控制并与MEF集成。例如,它允许您设置这样的注册,以便BarBaz实例获得具有不同参数的Foo实例:

builder.Register(c => new Bar(new Foo(param));
builder.Register(c => new Baz(new Foo(param2));

如果您想根据MEF中的某些逻辑(应用策略模式)使用同一接口的不同实例,请使用ExportMetadata属性。例如,如果您有IDbManager,并且有两个实现,比如一个Oracle和一个Sql,那么1.创建将保存元数据的元数据接口

public interface IDbManagerMetadata
{
    DataProvider DataProvider { get; }
}

2.创建如下所示的属性类

[MetadataAttribute]
public class DbManagerMetadataAttribute : Attribute, IDbManagerMetadata
{
    public DataProvider DataProvider { get; set; }
}
  1. 战略示例
public enum DataProvider
{
    Oracle,
    Sql,
}
[InheritedExport]
public interface IDbManager
{
    void Initialize();
}
[InheritedExport(typeof(IDbManager))]
public class DbManager : IDbManager
{
    public DbManager(DataProvider providerType)
    {
        _providerType = providerType;
    }
    public void Initialize()
    {
        Console.WriteLine("provider : {0}", _providerType);
    }
    public DataProvider _providerType { get; set; }
}

的两种不同实现

[Export(typeof(IDbManager))]
[DbManagerMetadata(DataProvider = DataProvider.Oracle)]
public sealed class OracleDataProvider : DbManager
{
    public OracleDataProvider():base(DataProvider.Oracle)
    {
    }
}

[Export(typeof(IDbManager))]
[DbManagerMetadata(DataProvider = DataProvider.Sql)]
public sealed class SqlDataProvider : DbManager
{
    public SqlDataProvider()
        : base(DataProvider.Sql)
    {
    }
}

您可以通过使用我们在第一步中创建的元数据接口来决定使用哪一个,如下面所示的存储库中所示

[Export]
public class Repository
{
    private IDbManager _dbManager;
    private readonly IEnumerable<Lazy<IDbManager, IDbManagerMetadata>> DbManagers;
    [ImportingConstructor]
    public Repository([ImportMany(typeof(IDbManager))]IEnumerable<Lazy<IDbManager, IDbManagerMetadata>> dbManagers)
    {
        this.DbManagers = dbManagers;
        var _dbManager = DbManagers.First(x => x.Metadata.DataProvider == DataProvider.Oracle).Value;
    }
    public void Execute()
    {
        var oracleDbManager = DbManagers.First(x => x.Metadata.DataProvider == DataProvider.Oracle).Value;
        oracleDbManager.Initialize();
        var sqlDbManager = DbManagers.First(x => x.Metadata.DataProvider == DataProvider.Sql).Value;
        sqlDbManager.Initialize();
    }
}