.net 在使用IoC容器时,如何将参数传递给构造函数?
啊!我在这里拉扯头发。我尝试使用IoC容器已经有一段时间了,在遇到一些您认为非常基本的问题之前,一切看起来都很好,比如将参数传递给构造函数 假设我在某个地方有一个类,其中包含可以由IoC解析的引用类和只能在运行时解析的值类型(或其他类型):.net 在使用IoC容器时,如何将参数传递给构造函数?,.net,ninject,unity-container,ioc-container,.net,Ninject,Unity Container,Ioc Container,啊!我在这里拉扯头发。我尝试使用IoC容器已经有一段时间了,在遇到一些您认为非常基本的问题之前,一切看起来都很好,比如将参数传递给构造函数 假设我在某个地方有一个类,其中包含可以由IoC解析的引用类和只能在运行时解析的值类型(或其他类型): public NFLFeedUnitOfWork(NFLFileType fileType, object feed, IConverterMappings<NFLFileType> nflConverterMappings, IDbContex
public NFLFeedUnitOfWork(NFLFileType fileType, object feed, IConverterMappings<NFLFileType> nflConverterMappings, IDbContext context)
: base(fileType, feed, nflConverterMappings, context, ContextType.NFL)
{
//new NFLContext(connstringname, setAutoDetectChanges)
}
如何将此代码转换为使用IoC?
也许是这样的
protected override IFeedUnitOfWork GetUnitOfWork(NFLFileType fileType, object feed, string connectionString)
{
return IFLFeedUnitOfWork(fileType, feed);
}
最后2个参数自动解析,前2个参数由我自己提供
2.)如何使用IoC将枚举、对象和值类型传入构造函数?(或者在这种特殊情况下不要使用它?)
无论如何,我们非常感谢您的帮助,特别是在第一点上。
我现在使用的是Unity,但是任何其他IoC容器都可以
我也不想将IoC容器传递到代码中,我只想在顶层的一个位置指定它。根据值的来源,您有两个不同的选项。(我只熟悉Ninject,我想Unity也有类似的功能) 如果数据依赖于其他服务或存储库,则可以将对象绑定到委托,以便在满足请求时解析该对象。例如:
Bind<NFLFileType>().ToMethod( context => context.Kernel.Get<IConfigProvider>().NFLFileType );
Bind<NFLFileType>().ToConstant( NFLFileType.MyValue ).WhenInjectedInto<NFLFeedUnitOfWork>();
Bind<NFLFileType>().ToConstant( NFLFileType.MyValue ).When(request => request.Target.Type.GetCustomAttributes(typeof(MyValueAttribute)) != null );
如果所有其他操作都失败,则可以将注入的接口绑定到类似于工厂模式的提供程序,以生成对象:
Bind<IFeedUnitOfWork>().ToProvider<UnitOfWorkProvider>();
Bind().ToProvider();
提供者知道如何根据上下文解析前2个参数
我在某个地方有一个类,它混合了一些参考类,可以
由IoC和只能
在运行时解析
这就是你错的地方。在编写组件时,不应将编译时依赖项与运行时数据混合。您的对象图应该是静态的(最好是无状态的),并且在构建完整的对象图之后,应该使用方法调用通过对象图传递运行时数据。这会大大简化应用程序的开发,因为它允许静态地验证对象图(使用工具、单元测试或使用纯DI),并且可以避免您现在遇到的麻烦
通常,您有两个选项来解决此问题:
公共接口IFeedUnitOfWorkProvider
{
IFeedUnitOfWork GetUnitOfWork(NFLFileType文件类型,对象提要);
}
这里的IFeedUnitOfWorkProvider
包含一个GetUnitOfWork
方法,该方法需要运行时参数作为输入。实现可能如下所示:
公共类FeedUnitOfWorkProvider:IFeedUnitOfWorkProvider
{
私有只读IConverterMappings converterMappings;
私有只读IContext上下文;
公共FeedUnitOfWorkProvider(IConverterMappings converterMappings,
IContext(上下文){
this.converterMappings=converterMappings;
this.context=上下文;
}
public IFeedUnitOfWork GetUnitOfWork(NFLFileType文件类型,对象提要){
返回新的NFLFeedUnitOfWork(文件类型、提要、this.converterMappings、,
这是(上下文);
}
}
这里有几点需要注意:
- 所有静态已知的依赖项都通过构造函数注入,而运行时值则通过方法调用注入
未知FeedUnitOfWorkProvider
值。它不是一个直接依赖项,提供者不必知道它的存在connectionString
- 假设
是一个在运行时不会更改的配置值(通常存储在应用程序的配置文件中),那么它可以像注入其他依赖项一样注入到connectionString
中。请注意,配置值与运行时值不同,因为它在应用程序的生命周期内不会更改NFLContext
公共接口IUserContext{
字符串CurrentUserName{get;}
}
此接口可以注入任何使用者。使用此抽象,使用者可以在运行时查询用户名。将用户名与其余请求数据一起传递通常会很尴尬,因为这将允许调用方更改(或忘记)用户名,从而使代码更难使用、更难测试、更容易出错。相反,我们可以使用IUserContext
:
public IFeedUnitOfWork GetUnitOfWork(NFLFileType文件类型,对象提要){
如果(this.userContext.CurrentUserName==“steven”){
返回新的AdminUnitOfWork(this.context);
}
返回新的NFLFeedUnitOfWork(文件类型、提要、this.converterMappings、,
这是(上下文);
}
一个IUserContext
实现的外观在很大程度上取决于您正在构建的应用程序的类型。对于ASP.NET,我设想如下:
公共类AspNetUserContext:IUserContext{
字符串CurrentUserName{
获取{return HttpContext.Current.User.Name;}
}
}
+
Bind<IFeedUnitOfWork>().ToProvider<UnitOfWorkProvider>();