C# 简单喷油器构造参数

C# 简单喷油器构造参数,c#,dependency-injection,simple-injector,C#,Dependency Injection,Simple Injector,我在一个项目中使用SimpleInjector作为DI容器 问题是我有一个SqliteStorage-类,它需要到数据库的路径。有多个数据库,因此我需要一种方法在创建时将路径注入到SqliteStorage-类 我的代码如下所示(简化了,没有接口): public类SqliteStorageOptions { 公共字符串路径{get;set;} } 公共类SqliteStorage { 私有只读字符串_路径; 公共SqliteStorage(SqliteStorageOptions) { _pa

我在一个项目中使用SimpleInjector作为DI容器

问题是我有一个
SqliteStorage
-类,它需要到数据库的路径。有多个数据库,因此我需要一种方法在创建时将路径注入到
SqliteStorage
-类

我的代码如下所示(简化了,没有接口):

public类SqliteStorageOptions
{
公共字符串路径{get;set;}
}
公共类SqliteStorage
{
私有只读字符串_路径;
公共SqliteStorage(SqliteStorageOptions)
{
_path=options.path;
}
}
公共类Db1
{
私有只读sqlite存储_sqlite;
公共Db1(sqlite存储sqlite)
{
_sqlite=sqlite;
}
}
公共类Db2
{
私有只读sqlite存储_sqlite;
公共Db1(sqlite存储sqlite)
{
_sqlite=sqlite;
}
}
//无di
var db1=new db1(new SqliteStorage(new SqliteStorageOptions{Path=“db1.db”});
var db2=newdb2(newsqlitestorage(newsqlitestorageoptions{Path=“db2.db”});
可能的解决办法:

  • SqliteStorageOptions
    作为参数包含在
    SqliteStorage
    中的每个方法中
  • SqliteStorage
  • 使用
    公共sqlitestoragecreate(SqliteStorageOptions)
    -方法创建一个
    SqliteStorageFactory
  • 那么,对于我的简单喷油器问题,是否有任何内置的解决方案,或者有人能提供另一个(更好的)解决方案

    谢谢

    编辑1:
    我添加了一些代码。
    Db1
    Db2
    都连接到sqlite数据库(不同的数据库,不同的模式)所以我想把所有SQLite的东西提取到它自己的类<代码> SQLITestRoGe>代码>。因此,<代码> SQLITestRoGe<代码>需要知道DB路径。< /P> < p>每个数据库连接可以有2个单独的一个。让我们考虑一个例子,首先我们需要为您的存储服务创建一个接口:

    public interface IStorage
    {
        void UsePath();
    }
    
    现在,让我们创建此存储服务的两个实现:

    public class RedisStorage: IStorage
    {
        private readonly string _path;
    
        public RedisStorage(string path)
        {
            _path = path;
        }
    
        public void UsePath()
        {
            Console.WriteLine($"Here's path: {_path}");
        }
    }
    
    public class SqlStorage: IStorage
    {
        private readonly string _path;
    
        public SqlStorage(string path)
        {
            _path = path;
        }
    
        public void UsePath()
        {
            Console.WriteLine($"Here's path: {_path}");
        }
    }
    
    用于区分IStorage实现的枚举:

    public class StorageSource
    {
        public enum StorageTypes
        {
            Redis=1,
            Sql=2
        }
    }
    
    完成后,让我们为存储源创建一个包装器:

    public interface IStorageWrapper
    {
        void DoStuff();
    }
    
    现在是一个棘手的部分,实例化存储包装器服务装饰器:

    public class StorageServiceWrapper: IStorageWrapper
    {
        private readonly Func<string, IStorage> _storage;
    
        public StorageServiceWrapper(Func<string, IStorage> storage)
        {
            _storage = storage;
        }
    
        public void UsePath()
        {
            _storage(StorageSource.StorageTypes.Redis.ToString()).DoStuff();
            //uncomment for sql
            //_storage(StorageSource.StorageTypes.Sql.ToString()).DoStuff();
        }
    }
    
    公共类StorageServiceWrapper:IStorageWrapper
    {
    专用只读功能存储器;
    公共存储服务包装器(Func存储)
    {
    _储存=储存;
    }
    公共void UsePath()
    {
    _存储(StorageSource.StorageTypes.Redis.ToString()).DoStuff();
    //取消sql的注释
    //_存储(StorageSource.StorageTypes.Sql.ToString()).DoStuff();
    }
    }
    
    为此,您需要在Startup.cs中注册类,如下所示:

    services.AddScoped<IStorageWrapper, StorageServiceWrapper>();  
      
    services.AddSingleton<RedisStorage>();  
    services.AddSingleton<SqlStorage>();  
      
    services.AddTransient<Func<string, IStorage>>(serviceProvider => key =>  
    {  
        switch (key)  
        {  
            case "Redis":  
                return serviceProvider.GetService<RedisStorage>();  
            default:  
                return serviceProvider.GetService<SqlStorage>();  
        }  
    }); 
    
    services.addScope();
    services.AddSingleton();
    services.AddSingleton();
    services.AddTransient(serviceProvider=>key=>
    {  
    开关(钥匙)
    {  
    案例“Redis”:
    返回serviceProvider.GetService();
    违约:
    返回serviceProvider.GetService();
    }  
    }); 
    

    这不如调用
    \u storage.DoStuff()漂亮如果你还想保持它的便利性,考虑管理你的设置文件,用你需要的CONN字符串注入适当的IOFILE实例并注册一个工厂方法。

    < P>哪种解决方案最好取决于你是否需要自动布线。(自动构造函数注入)或不使用。使用条件注册(使用
    RegisterConditional
    )是一个不错的选择,但您必须知道,它仅限于基于其直接父项确定注入。这意味着您不能基于其父项使
    SqliteStorageOptions
    有条件(要么
    Db1
    要么
    Db2

    如果
    Db1
    Db2
    类仅依赖于
    SqliteStorage
    并且不需要任何其他依赖项,则自动连接不是真正的问题,您的注册可以简单到如下所示:

    container.Register<Db1>( () => new Db1(new SqliteStorage(new SqliteStorageOptions { Path = "db1.db" })); container.Register<Db2>( () => new Db2(new SqliteStorage(new SqliteStorageOptions { Path = "db2.db" }); 在这个代码片段中,
    Db1
    Db2
    都是“正常”注册的,而
    SqliteStorage
    注册是基于i使用者有条件地注入的


    此注册更复杂,因为
    RegisterConditional
    需要提供一个
    registration
    实例:没有直接接受
    Func
    工厂委托的
    RegisterConditional
    重载。

    您显示的代码有什么问题吗?我不确定您是否理解问题所在正在尝试解决。DI框架应该如何知道注入哪条路径?如果这是可以根据DI框架提供的其他服务提供的值来确定的,那么您应该能够为
    SqliteStorageOptions
    注册一个工厂方法,一切都将“正常工作”如果没有,DI容器就无法知道注入什么,因此您需要使用一种可能的解决方案(我建议#1或#3)您提到过。您有多个数据库,但它们都有相同的模式,还是不同的模式?这是回答您问题的一个重要区别。我添加了一些代码。@StriplingWarrior
    Db1,Db2
    知道它们的路径。@Steven不同的数据库,不同的模式。
    SqliteStorage
    是对sqlite的抽象-stuff.我添加了一些代码。我已经为dbs提供了
    Db1、Db2
    -类。这两个类都依赖于
    SqliteStorage
    ,这应该会将sqlite内容抽象掉。因此
    SqliteStorage
    需要到db的路径。 container.Register<Db1>(); container.Register<Db2>(); container.RegisterConditional<SqliteStorage>( Lifestyle.CreateRegistration( () => new SqliteStorage(new SqliteStorageOptions { Path = "db1.db" }), container), c => c.Consumer.ImplementationType == typeof(Db1)); container.RegisterConditional<SqliteStorage>( Lifestyle.CreateRegistration( () => new SqliteStorage(new SqliteStorageOptions { Path = "db2.db" }), container), c => c.Consumer.ImplementationType == typeof(Db2));