我使用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...
}
}
第三类依赖于IDatabase
public class DataService: IDataService
{
public DataService(IDatabase database)
{
database.DoSomething();
}
}
模块使用Unity注册每个类,并为两个IDatabase类型指定特定名称,以便区分它们:
container.RegisterType<IDatabase, SQLDatabase>("SQLDatabase");
container.RegisterType<IDatabase, OracleDatabase>("OracleDatabase");
container.RegisterType<IDataService, DataService>();
我需要创建一个Consumer的实例,此时我想指定Unity使用/注入实现IDatabase的两种类型中的哪一种,但我不知道如何告诉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使用特定的命名类型解析IDatabase类型,并将其传递给依赖对象的构造函数,但是在运行时执行它?
答案 0 :(得分:3)
我会改变两件事,我会尽量确保尽可能接近源代码处理这些魔术字符串,并尝试确保我的代码与容器无关。
我会有以下界面:
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()
。< / p>
现在所有的运行时代码都与容器无关,并且魔术字符串在其源旁边处理。
答案 1 :(得分:2)
我能够使用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);
}
}
答案 2 :(得分:0)
我有一个类似的要求,我需要在运行时解析'widgetbuilder'类型。在我的Unity配置中,我注册了两种类型的小部件构建器: -
.some()
然后我在运行时通过以下方法解决它们: -
container.RegisterType<IWidgetBuilder, SinglePointWidgetBuilder>("SinglePointWidgetBuilder");
container.RegisterType<IWidgetBuilder, CurrentVsTargetWidgetBuilder>("CurrentVsTargetWidgetBuilder");