摘要

DI容器的一个责任是管理他创建的对象的生命周期。他应该决定什么时候创建一个给定类型的对象,什么时候使用已经存在的对象。他还需要在对象不需要的时候处理对象。Ninject在不同的情况下管理对象的生命周期提供了强大的支持。在我们定义一个绑定的时候,定义创建对象的范围。在那个范围内,对象将被重用,每次绑定只存在一次。注意,对象不允许依赖于生命周期短自己小的对象。

1、暂时范围

在暂时态范围内,对象生命周期不被Ninject进行管理。任何时候请求一个类型的对象,都将创建一新对象。Ninject不管理保持创建的对象或者在范围内处理他。这是Ninject默认的范围。如果不指定范围,默认是暂时态。在上一篇文章里,ConsoleLogger和MailServer对象都是暂时态,因为没有指定他的范围。

2、单例范围

有时候我们不想每次需要的时候都创建一个新的对象,这时候使用单例。有两种方法创建单例。一种是使用单例模式。一种是使用Ninject方法InSingletonScope。
1)使用单例模式:

 class ConsoleLogger:ILogger
{
public static readonly ConsoleLogger Instance = new ConsoleLogger();
private static ConsoleLogger()
{
// Hiding constructor
}
public void Log(string message)
{
Console.WriteLine("{0}: {1}", DateTime.Now, message);
}
}

然后在Bind方法后调用ToConstant方法指定静态只读对象ConsoleLogger.Instance为常量对象。

kernel.Bind<ILogger>().ToConstant(ConsoleLogger.Instance);

2)使用方法InSingletonScope:

kernel.Bind<ILogger>().To<ConsoleLogger>().InSingletonScope();

如果要给MailServerConfig类对象设置单例,则先调用ToSelf方法将他绑定自身,然后再调用方法InSingletonScope。

kernel.Bind<MailServerConfig>().ToSelf().InSingletonScope();

3、线程范围

如果定义在线程范围内,每一个线程将只创建一个给定类型的对象。对象的生命周期跟对象所在的线程一样长。

调用方法InThreadScope创建线程范围:

kernel.Bind<object>().ToSelf().InThreadScope();

创建两个Test方法测试线程范围。

 using Ninject;
using NUnit.Framework;
using System.Threading; namespace Demo.Ninject
{
[TestFixture]
class NinjectTest
{
[Test]
public void ReturnsTheSameInstancesInOneThread()
{
using (var kernel = new StandardKernel())
{
kernel.Bind<object>().ToSelf().InThreadScope();
var instance1 = kernel.Get<object>();
var instance2 = kernel.Get<object>();
Assert.AreEqual(instance1, instance2);
}
} [Test]
public void ReturnsDifferentInstancesInDifferentThreads()
{
var kernel = new StandardKernel();
kernel.Bind<object>().ToSelf().InThreadScope();
var instance1 = kernel.Get<object>();
new Thread(() =>
{
var instance2 = kernel.Get<object>();
Assert.AreNotEqual(instance1, instance2);
kernel.Dispose();
}).Start();
}
}
}

第一个方法在同一个线程内请求了两个object对象,他们是相同的实例。第二个方法先在主线程内请求一个object实例,然后开启另一个线程请求另一个实例,他们不是相同的实例。

需要添加NUnit和NUnit.Console才能测试上面的方法。我使用的是NUnit 2.6.4和NUnit.Console 2.0.0。

4、请求范围

请求范围在web应用程序里非常有用。可以在相同的请求范围内得到一个单例的对象。一旦一个请求被处理,另一个请求到来,Ninject创建新的对象实例,并保持他直到请求结束。

调用方法InRequestScope设置请求范围,例如:

kernel.Bind<MailServerConfig>().ToSelf().InRequestScope();

需要添加Ninject.Web.Common引用才能够调用InRequestScope方法。

5、自定义范围

自定义范围让我们定义我们自己的范围,在这个范围内保持一类型的唯一对象。只要提供的回调方法返回的对象引用是一样的,Ninject在这个范围内返回相同的实例。只要返回的对象引用变了,将创建一新的指定类型的对象。创建的对象实例将一直保存在缓存里,直到返回的范围对象被垃圾回收器回收。一旦范围对象被垃圾回收器回收,Ninject创建的所有的对象实例将被从缓存中释放和处理。

调用InScope方法传入Lamda表达式定义自定义返回。例如:

kernel.Bind<object>().ToSelf().InScope(ctx => User.Current);

用例子来介绍自定义范围:

1)创建User类。

     class User
{
public string Name { get; set; }
public static User Current { get; set; }
}

2)创建函数ReturnsTheSameInstancesForAUser。

         [Test]
public void ReturnsTheSameInstancesForAUser()
{
using (var kernel = new StandardKernel())
{
kernel.Bind<object>().ToSelf().InScope(ctx => User.Current);
User.Current = new User();
var instance1 = kernel.Get<object>();
User.Current.Name = "Foo";
var instance2 = kernel.Get<object>();
Assert.AreEqual(instance1, instance2);
}
}

虽然User.Current.Name的值变了,但是User.Current的引用没变。因此,两次请求返回的对象是同一个对象。

3)创建函数ReturnsDifferentInstancesForDifferentUsers。

         [Test]
public void ReturnsDifferentInstancesForDifferentUsers()
{
using (var kernel = new StandardKernel())
{
kernel.Bind<object>().ToSelf().InScope(ctx => User.Current);
User.Current = new User();
var instance1 = kernel.Get<object>();
User.Current = new User();
var instance2 = kernel.Get<object>();
Assert.AreNotEqual(instance1, instance2);
}
}

因为改变了User.Current对象引用,因此,两次请求返回的对象是不同的对象。

你可能注意到了回调函数提供了一个名字是ctx的IContext参数。这个对象提供了绑定的用来创建范围对象的上下文环境。自定义范围是最灵活最有用的范围。其实其他范围都可以用自定义范围来实现。

线程范围:

kernel.Bind<object>().ToSelf().InScope(ctx=>Thread.CurrentThread);

请求范围:

kernel.Bind<object>().ToSelf().InScope(ctx=>HttpContext.Current);

可以使用Release方法强制释放创建的对象实例。

 var myObject = kernel.Get<MyService>();
..
kernel.Release(myObject);

Ninject之旅之三:Ninject对象生命周期的更多相关文章

  1. Hibernate的三种状态及对象生命周期

        理解Hibernate的三种状态,更利于理解Hibernate的运行机制,这些可以让你在开发中对疑点问题的定位产生关键性的帮助. 三种状态 临时状态(Transient):在通过new关键字, ...

  2. .Net组件程序设计之对象生命周期

    .Net组件程序设计之对象生命周期 .NET 垃圾回收 IDisposable() Using语句 .NET 垃圾回收 是CLR管理着垃圾回收器,垃圾回收器监控着托管堆,而我们使用的对象以及系统启动是 ...

  3. iOS视图控制对象生命周期

    iOS视图控制对象生命周期-init.viewDidLoad.viewWillAppear.viewDidAppear.viewWillDisappear.viewDidDisappear的区别及用途 ...

  4. IOS 视图控制对象生命周期-init、viewDidLoad、viewWillAppear、viewDidAppear、viewWillDisappear等的区别及用途

    iOS视图控制对象生命周期-init.viewDidLoad.viewWillAppear.viewDidAppear.viewWillDisappear.viewDidDisappear的区别及用途 ...

  5. 【转】【iOS知识学习】_视图控制对象生命周期-init、viewDidLoad、viewWillAppear、viewDidAppear、viewWillDisappear等的区别及用途

    原文网址:http://blog.csdn.net/weasleyqi/article/details/8090373 iOS视图控制对象生命周期-init.viewDidLoad.viewWillA ...

  6. _视图控制对象生命周期-init、viewDidLoad、viewWillAppear、viewDidAppear、viewWillDisappear等的区别及用途

    iOS视图控制对象生命周期-init.viewDidLoad.viewWillAppear.viewDidAppear.viewWillDisappear.viewDidDisappear的区别及用途 ...

  7. ASP.NET Core Web API下事件驱动型架构的实现(二):事件处理器中对象生命周期的管理

    在上文中,我介绍了事件驱动型架构的一种简单的实现,并演示了一个完整的事件派发.订阅和处理的流程.这种实现太简单了,百十行代码就展示了一个基本工作原理.然而,要将这样的解决方案运用到实际生产环境,还有很 ...

  8. Python学习手册之内部方法、操作符重载和对象生命周期

    在上一篇文章中,我们介绍了 Python 的类和继承,现在我们介绍 Python 的内部方法.操作符重载和对象生命周期. 查看上一篇文章请点击:https://www.cnblogs.com/dust ...

  9. Servlet对象生命周期(四)

    一.Servlet对象生命周期 一下图片说明上图第7点 destroy()方法是在停止tomcat服务器时执行 https://pan.baidu.com/s/1mgTabWW#list/path=% ...

随机推荐

  1. 关于C语言的一些trick

    很多东西已经记不起来了,想到一点写一点,碰到一点写一点,慢慢累积. 关于# #在宏定义中用于替换传入变量的字符,例如: #define whole_operation(n)  do { printf( ...

  2. C#中dynamic的正确用法

    C#中dynamic的正确用法  http://www.cnblogs.com/qiuweiguo/archive/2011/08/03/2125982.html dynamic是FrameWork4 ...

  3. MYCAT 配置(转)

     server.xml配置 <?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE mycat:se ...

  4. Javascript模式(第三章字面量与构造函数)------读书笔记

    一 对象字面量 1.1对象字面量的语法 1,对象键值对哈希表,在其他的编程语言中称之为“关联数组”, 2 键值对里面的值,可以是原始类型也可以是其他类型的对象,称之为属性,函数称之为方法 3 自定义对 ...

  5. [PHP] - Apache + PHP 环境搭建

    Apache和PHP的版本分别为: httpd-2.4.9-win64-VC11.zip php-5.6.9-Win32-VC11-x64.zip 下载地址: php-5.6.9-Win32-VC11 ...

  6. Code Page 编码

    Identifier .NET Name Additional information 037 IBM037 IBM EBCDIC US-Canada 437 IBM437 OEM United St ...

  7. 安装ntp

    #yum -y install ntp#service ntpd restart#vi /etc/ntp.confserver 0.aisa.pool.ntp.org iburstserver 1.a ...

  8. Automation Test in Maya Plugin Development

    现状和问题- 开发插件的功能A的时候随手建立场景, 测试插件的功能A. 测试通过后,测试场景就被丢掉.- 发现插件的功能A有bug时, 修改代码, 然后随手建立场景, 测试bug. 测试通过后,测试场 ...

  9. (document).height()与$(window).height()

    jQuery(window).height()代表了当前可见区域的大小,而jQuery(document).height()则代表了整个文档的高度,可视具体情况使用. 注意当浏览器窗口大小改变时(如最 ...

  10. windows10降低IE版本

    win10支持的最低IE版本为IE10,现在IE最新版本为IE11,而win10自带的浏览器是microsoft  EDGE ,这给 以前的老系统带来很多不便,为了支持以前的老系统,只有降低IE浏览器 ...