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

时间:2012-03-29 18:31:06

标签: c# dependency-injection inversion-of-control mef

我知道有很多关于使用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框架的组合实现这一目标?
  4. 感谢您的帮助。 :)郎,问候,Yogesh Jagota

2 个答案:

答案 0 :(得分:2)

  

如果上述两个问题的答案都是否定的,那么还有其他方法可以通过MEF和其他DI / IOC框架的组合实现这一目标吗?

我认为问题1和问题2的答案确实没有。

我会尝试AutoFac,它会为您提供更精细的控制和integrates with MEF。例如,它允许您设置这样的注册,以便BarBaz实例使用不同的参数获取其Foo实例:

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

答案 1 :(得分:1)

如果要在MEF中使用相同接口的不同实例(取决于某些逻辑(应用策略模式)),可以使用ExportMetadata Attribute。 例如,如果你有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 {     甲骨文,     SQL中, } [InheritedExport] 公共接口IDbManager {     void Initialize(); }

    [InheritedExport(typeof运算(IDbManager))] 公共类DbManager:IDbManager {     public DbManager(DataProvider providerType)     {         _providerType = providerType;     }

    public void Initialize()
    {
        Console.WriteLine("provider : {0}", _providerType);
    }
    
    public DataProvider _providerType { get; set; }
    

    }

  2. 两种不同的实现

    [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();
        }
    }