C# 简单喷油器构造参数
我在一个项目中使用SimpleInjector作为DI容器 问题是我有一个C# 简单喷油器构造参数,c#,dependency-injection,simple-injector,C#,Dependency Injection,Simple Injector,我在一个项目中使用SimpleInjector作为DI容器 问题是我有一个SqliteStorage-类,它需要到数据库的路径。有多个数据库,因此我需要一种方法在创建时将路径注入到SqliteStorage-类 我的代码如下所示(简化了,没有接口): public类SqliteStorageOptions { 公共字符串路径{get;set;} } 公共类SqliteStorage { 私有只读字符串_路径; 公共SqliteStorage(SqliteStorageOptions) { _pa
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
我添加了一些代码。
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)您提到过。您有多个数据库,但它们都有相同的模式,还是不同的模式?这是回答您问题的一个重要区别。我添加了一些代码。@StriplingWarriorDb1,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));