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

C# MEF:使用CreationPolicy.NonShared时将不同的构造函数参数传递给部件,c#,dependency-injection,inversion-of-control,mef,C#,Dependency Injection,Inversion Of Control,Mef,我知道有很多关于使用MEF的构造函数参数注入的问题,但是我的有点不同 我想知道,当我使用PartCreationPolicy(CreationPolicy.NonShared)和GetExportedValue的组合时,有没有办法将不同的参数值传递给零件的构造函数 例如: [PartCreationPolicy(CreationPolicy.NonShared)] [Export] public partial class Foo { [ImportingConstructor]

我知道有很多关于使用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>();
container.ComposeExportedValue(“SomeParam”,“someValue…”);
var实例=container.GetExportedValue();
在上面的示例中,我只能使用
ComposeExportedValue
一次,因为再次运行它将导致
ChangeRejectedException


因此,我的问题是:

  • 在上述场景中,对于每个新实例,是否有其他方法可以更改
    SomeParam
    的值
  • 如果没有,那么在不使用任何其他DI框架的情况下,还有哪些方法可以实现这一点?我想到的一件事是创建一个服务来公开类似于
    System.Collections.Concurrent.ConcurrentQueue
    的内容,在调用
    GetExportedValue
    之前,我将一个参数值排队,然后将该值从部件的构造函数中出列。但这是一种黑客行为,而且造成的问题比解决的问题还多
  • 如果以上两个问题的答案都是否定的,那么有没有其他方法可以结合MEF和其他DI/IOC框架来实现这一点
  • 谢谢你的帮助。:)
    问候,
    约格什·贾戈塔

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

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

    我会尝试使用更细粒度的控件和。例如,它允许您像这样设置注册,以便
    Bar
    Baz
    实例使用不同的参数获取其
    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; }
    }
    
    二,。创建属性类,如下所示

    [MetadataAttribute]
    public class DbManagerMetadataAttribute : Attribute, IDbManagerMetadata
    {
        public DataProvider DataProvider { get; set; }
    }
    
  • 策略示例
  • 公共枚举数据提供程序
    {
    神谕
    Sql,
    }
    [继承导出]
    公共接口管理器
    {
    void初始化();
    }
    [InheriteExport(typeof(IDbManager))]
    公共类DbManager:IDbManager
    {
    公共DbManager(数据提供程序提供程序类型)
    {
    _providerType=providerType;
    }
    公共无效初始化()
    {
    WriteLine(“提供程序:{0}”,_providerType);
    }
    公共数据提供程序_providerType{get;set;}
    }
    
    和两种不同的实现

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

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

    [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();
        }
    }
    
    [导出]
    公共类存储库
    {
    私人IDbManager_dbManager;
    私有只读IEnumerable数据库管理器;
    [导入构造函数]
    公共存储库([ImportMany(typeof(IDbManager))]IEnumerable DBManager)
    {
    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;
    oracledmanager.Initialize();
    var sqlDbManager=DbManagers.First(x=>x.Metadata.DataProvider==DataProvider.Sql).Value;
    sqlDbManager.Initialize();
    }
    }
    
    我正在研究AutoFac/MEF集成,但在使用注册器ComposablePartCatalog时如何处理注册?我不能在这里使用
    注册
    ,因为它是由AutoFac自动完成的。我如何告诉AutoFac某个导出需要使用我提供的参数的非默认构造函数实例化,而不使用
    [ImportingConstructor]
    ?@Yogesh:您可以让一些组件注册到AutoFac(当您需要细粒度控制时),其他组件则使用MEF导出(当您需要动态发现插件时)。但对于同一个组件,您不能将两者混合使用。另一个选项是完全切换到AutoFac;您可以在需要时使用它来获得类似MEF的动态发现。它实际上是有效的。方法是使用
    IContainer
    Update
    方法,该方法允许向现有容器添加新注册。谢谢。:)为不同实例设置具有不同值的ImportingConstructor参数的答案在哪里?@Sreenath dbmanagermetataAttribute是您的答案
    [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();
        }
    }