在运行时解决构造函数依赖(不带属性)
本文关键字:属性 函数依赖 运行时 解决 | 更新日期: 2023-09-27 18:15:25
我使用Unity进行依赖注入,我想在运行时控制,哪种特定类型被解析并作为依赖传递给构造函数。
我有一个接口:
public interface IDatabase
{
void DoSomething();
}
由两个类实现:
public class SQLDatabase : IDatabase
{
public void DoSomething()
{
//Do Something on a SQL server database...
}
}
public class OracleDatabase : IDatabase
{
public void DoSomething()
{
//Do Something on an Oracle database...
}
}
第三个类依赖于iddatabase
public class DataService: IDataService
{
public DataService(IDatabase database)
{
database.DoSomething();
}
}
模块在Unity中注册每个类,两个iddatabase类型被赋予特定的名称,以便它们可以区分:
container.RegisterType<IDatabase, SQLDatabase>("SQLDatabase");
container.RegisterType<IDatabase, OracleDatabase>("OracleDatabase");
container.RegisterType<IDataService, DataService>();
我需要创建一个Consumer的实例,在这一点上,我想指定两种类型中的哪一种实现iddatabase将被Unity使用/注入,但我不知道如何告诉Unity构建/解析哪一种特定类型?我想我想要这样的东西(伪代码):
public class Consumer
{
IDataService dataService = null;
public Consumer(string runtimeChoice)
{
if (runtimeChoice == "SQLSERVER")
{
dataService = _container.Resolve<IDataService>("SQLDatabase");
}
else if (runtimeChoice == "Oracle")
{
dataService = _container.Resolve<IDataService>("OracleDatabase");
}
}
}
那么,我如何告诉Unity解析iddatabase类型,使用特定的命名类型,并将其传递给依赖对象的构造函数,但在运行时执行?
有两件事我要改变,我会尽量确保那些神奇的字符串处理尽可能接近他们的源,我会尽量确保我的代码是容器无关的。
我将有以下接口:
public interface IDataServiceFactory
{
IDataService CreateSqlDataService();
IDataService CreateOracleDataService();
}
使用如下实现:
public class DataServiceFactory : IDataServiceFactory
{
private readonly Func<IDataService> _sqlDataServiceFactory;
private readonly Func<IDataService> _oracleDataServiceFactory;
public DataServiceFactory(Func<IDataService> sqlDataServiceFactory, Func<IDataService> oracleDataServiceFactory)
{
_sqlDataServiceFactory = sqlDataServiceFactory;
_oracleDataServiceFactory = oracleDataServiceFactory;
}
public IDataService CreateSqlDataService()
{
return _sqlDataServiceFactory();
}
public IDataService CreateOracleDataService()
{
return _oracleDataServiceFactory();
}
}
然后我将此注册到您的IUnityContainer
,如下所示:
_container.RegisterType<IDataService, DataService>("SQLDataService",
new InjectionConstructor(new ResolvedParameter<IDatabase>("SQLDatabase")));
_container.RegisterType<IDataService, DataService>("OracleDataService",
new InjectionConstructor(new ResolvedParameter<IDatabase>("OracleDatabase")));
_container.RegisterType<IDataServiceFactory, DataServiceFactory>(new InjectionConstructor(
new ResolvedParameter<Func<IDataService>>("SQLDataService"),
new ResolvedParameter<Func<IDataService>>("OracleDataService"));
现在,无论之前创建Consumer
实例的是什么,现在都应该依赖于IDataServiceFactory
,并且应该处理运行时值以调用正确的方法CreateSqlDataService()
或CreateOracleDataService()
。
所有的运行时代码现在都是容器无关的,并且魔术字符串将在其源代码旁边处理。
我能够使用DependencyOverride解决正确的类型,它本身从unity容器中获得所需的类型。因此消费者变成:
public class Consumer
{
IDataService dataService = null;
public Consumer(string runtimeChoice)
{
DependencyOverride<IDatabase> dependency = null;
if (runtimeChoice == "SQLSERVER")
{
dependency = new DependencyOverride<IDatabase>
(Container.Resolve<IDatabase>("SQLDatabase"));
}
else if (runtimeChoice == "Oracle")
{
dependency = new DependencyOverride<IDatabase>
(Container.Resolve<IDatabase>("OracleDatabase"));
}
dataService = _container.Resolve<IDataService>(dependency);
}
}
我有一个类似的需求,我需要在运行时解析'widgetbuilder'类型。在我的Unity配置中,我注册了两种类型的小部件构建器:
container.RegisterType<IWidgetBuilder, SinglePointWidgetBuilder>("SinglePointWidgetBuilder");
container.RegisterType<IWidgetBuilder, CurrentVsTargetWidgetBuilder>("CurrentVsTargetWidgetBuilder");
然后在运行时解析它们:-
var container = UnityConfig.GetConfiguredContainer();
var widgetBuilder = container.Resolve<IWidgetBuilder>("SinglePointWidgetBuilder");