.net 在使用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

啊!我在这里拉扯头发。我尝试使用IoC容器已经有一段时间了,在遇到一些您认为非常基本的问题之前,一切看起来都很好,比如将参数传递给构造函数

假设我在某个地方有一个类,其中包含可以由IoC解析的引用类和只能在运行时解析的值类型(或其他类型):

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>();