Ninject使用教程

news/2024/2/21 3:20:28

.net framework 下可以使用 Ninject 作为 DI 容器.

关于构造函数和属性注入的对比

  • 不推荐属性注入的主要原因是:
  1. 测试困难: 属性注入导致依赖硬编码在类中,不能通过构造函数正确初始化,允许测试。
  2. 顺序依赖: 当一个类依赖于多个属性时,它们的初始化顺序可能存在依赖关系。但是属性注入无法保证依赖的正确顺序。
  3. 难以debug: 因为属性注入是在运行时发生的,调试时很难追踪并理解。
  4. 难以理解: 对于一个新代码许多人来说,属性注入的依赖关系并不易于理解。
  • 相比之下,构造函数注入则不具备这些缺点:
  1. 在构造函数中明确地声明所有的依赖
  2. 通过构造函数的参数顺序保证了正确的依赖注入顺序
  3. 在代码中明确地声明了依赖关系,易于理解和调试
  4. 允许通过传递 mock 依赖实现单元测试

Ninject 简单示例

  1. StandardKernel 为 Ninject 的 DI 容器
  2. 使用容器完成一个接口和实现类的注入.
  3. 使用容器获取了一个接口的实现类对象.
using Ninject;public interface IHello 
{void SayHello();
}public class HelloImpl : IHello
{public void SayHello() {Console.WriteLine("Hello from Ninject!");   }
}class Program
{static void Main(string[] args){// Create the kernelIKernel kernel = new StandardKernel();// Register the interface and implementationkernel.Bind<IHello>().To<HelloImpl>();  // Resolve the dependencyIHello hello = kernel.Get<IHello>();// Use the dependencyhello.SayHello();}  
}

Ninject 常用的几种绑定方式

  1. ToSelf(), 最简单, 直接绑定接口和实现类
  2. To (), 最常见, 显式绑定接口到实现类
  3. ToMethod(), 最强大, 绑定到一个动态创建的实现类实例
  4. ToConstructor(), 使用一个构造函数注入实现类实例

Ninject 使用一个构造函数注入实现类实例

下面的实现类构造器有一个string参数, 代码演示如何使用 Ninject 实现构造函数 .

interface IHello 
{void SayHello();
}class HelloImpl : IHello
{public HelloImpl(string name){Name = name;   }public string Name { get; set; }public void SayHello() {Console.WriteLine($"Hello {Name}!");   }
}class Program
{static void Main(string[] args){IKernel kernel = new StandardKernel();kernel.Bind<IHello>().To<HelloImpl>();// Bind constructor argumentkernel.Bind<string>().ToConstant("John");IHello hello = kernel.Get<IHello>();hello.SayHello();  // Prints "Hello John!"}
}

Ninject 使用 ToConstructor() 实现多参数构造器注入实例

kernel.Bind<IGreetingService>().ToConstructor(ctr => {ctr.WithConstructorArgument("name", "John");ctr.WithConstructorArgument("age", 30);ctr.WithConstructorArgument("isActive", true);   }
);

Ninject 使用ToMethod() 注入实现类实例的代码

kernel.Bind<IMyService>().ToMethod(ctx => {if(IsTestEnv()) {return new TestService();  } else {  return new ProdService();}
});

Ninject 按名称绑定

定义两个实现类:

public interface IGreetingService {...}public class EnglishGreeting : IGreetingService {...}
public class ChineseGreeting : IGreetingService {...}

完成绑定和解析:

//绑定
kernel.Bind<IGreetingService>().To<EnglishGreeting>().Named("english");
kernel.Bind<IGreetingService>().To<ChineseGreeting>().Named("chinese");//解析
IGreetingService english = kernel.Get<IGreetingService>("english");
IGreetingService chinese = kernel.Get<IGreetingService>("chinese");

Ninject 如何设置绑定作用域

kernel.Bind<IMyService>().To<MyService>().InSingletonScope();

在 Ninject 中,还有其他作用域可用:

  • InTransientScope() : Transient是默认作用域,每次解析新建实例(非单例)
  • InThreadScope(): 与线程绑定,每个线程解析相同实例
  • InRequestScope(): 与请求绑定,每个请求解析相同实例
  • InSingletonScope: 每次解析依赖时返回相同的实例。

Ninject 真实案例代码

代码讲解:

  1. BusinessService 有logger和name两个构造函数参数
  2. 我们分别为这两个参数绑定值或依赖
  3. 使用 ToSelf(), BusinessService 本身作为依赖
  4. 然后解析 BusinessService 依赖时,Ninject 将先自动创建ConsoleLogger, 然后自动创建 BusinessService
interface ILogger {void LogInfo(string message);
}class ConsoleLogger : ILogger {public ConsoleLogger(string name) { ... }public void LogInfo(string message) { ... }
}class BusinessService {private ILogger logger;public BusinessService(ILogger logger, string name) {this.logger = logger;this.Name = name;   }public string Name { get; }}class Program
{static void Main() {IKernel kernel = new StandardKernel();// 绑定 logger 参数, 传入 "App"kernel.Bind<ILogger>().To<ConsoleLogger>();kernel.Bind<string>().ToConstant("App");// 绑定名称 string 参数kernel.Bind<string>().ToConstant("Business Service");// 绑定服务类, 没有接口, 所以绑定到自身kernel.Bind<BusinessService>().ToSelf();        //Ninject 将自动使用构造器 获取 BusinessService 对象var service = kernel.Get<BusinessService>();service.logger.LogInfo("Service Started!");    }
}

注册和解析不在一个文件的示例

下面代码中, 在Program.cs 中进行绑定一个singleton 实例, 在MainForm.cs 中进行解析实例. 要点:

  1. 将 Ninject 容器定义为静态属性, 其他类可以通过 Program.Kernel 来访问容器
// Program.cs
static class Program  
{public static IKernel Kernel { get; }  static Program() {Kernel = new StandardKernel();}
}
public partial class MainForm : Form
{public MainForm(){InitializeComponent();  // 解析依赖var service = Program.Kernel.Get<ISomeService>();}
}

https://www.xjx100.cn/news/306129.html

相关文章

MySQL- 存储引擎

MySQL体系结构 连接层 最上层是一些客户端和链接服务&#xff0c;包含本地sock 通信和大多数基于客户端/服务端工具实现的类似于 TCP/IP的通信。主要完成一些类似于连接处理、授权认证、及相关的安全方案。在该层上引入了线程 池的概念&#xff0c;为通过认证安全接入的客户端…

更多的 bash shell 命令

章节目录&#xff1a; 一、监测进程1.1 探查进程1.2 实时监测进程1.3 结束进程 二、监测磁盘空间2.1 挂载存储设备2.2 使用 df 命令2.3 使用 du 命令 三、处理数据文件3.1 数据排序3.2 数据搜索3.3 数据压缩3.4 数据归档 四、结束语 本章内容&#xff1a; 进程管理获取磁盘统计…

Java如何判空

目录 前言 List的判空 String的判空 Optional 4.1 Optional对象的创建 4.2使用场景 前言 实际项目中我们会有很多地方需要判空校验&#xff0c;如果不做判空校验则可能产生NullPointerException异常。 针对异常的处理我们在上一篇有提及&#xff1a; 先来看一下实际项目…

把Kubernetes用于微服务管理的最佳实践

把Kubernetes用于微服务管理的最佳实践 一、 引言1 什么是 Kubernetes2 Kubernetes 的优势和应用场景3 为什么使用 Kubernetes 部署容器化应用程序 二、 准备工作1 安装 Kubernetes2 准备容器镜像3 准备 Kubernetes 配置文件 三、 部署应用程序1 创建 Kubernetes 命名空间2 创建…

Solidity中的函数和事件

Solidity是一种用于编写智能合约的编程语言&#xff0c;它是以太坊平台上最常用的语言之一。在Solidity中&#xff0c;函数和事件是合约的两个关键组成部分。函数用于定义合约中的行为和逻辑&#xff0c;而事件则用于实现合约与外部应用程序之间的通信和交互。本文将深入探讨So…

【mongoDB】mongodb权限验证 || mongodb重启 || mongodb常用命令

mongodb版本号 6.0 前言 mongoDB刚开始无需密码登录mongoDB有3默认数据库&#xff0c;分别为&#xff1a; admin 超级用户&#xff0c;能对所有数据库操作&#xff0c;执行管理员命令config 分片集群配置的数据库local 分片集群锁信息的集合test 这个数据库一般是隐式创建的&…

辉哥带你学hive第一讲 hive基本介绍以及环境搭建

文章目录 1.Hive介绍1.1 hive 基本情况1.2 Hive架构原理1.3 Hive 安装1.4 元数据配置1.5 hive 服务部署1.6Hive常用交互命令1.6.1 Hive参数配置方式1.Hive介绍 1.1 hive 基本情况 hive基于Hadoop的一个数据仓库工具,可以将结构化的数据文件映射为一张表。 Hive是一个Hadoop客…

Apache Hive SQL DQL

Hive SQL--DQL-Select select语法树 SELECT [ALL | DISTINCT] select_expr, select_expr, ... FROM table_reference JOIN table_other ON expr [WHERE where_condition] [GROUP BY col_list [HAVING condition]] [CLUSTER BY col_list | [DISTRIBUTE BY col_list] [SORT BY|…