zoukankan      html  css  js  c++  java
  • Ninject的使用

    摘要

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

    1、暂时范围

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

     1 namespace Ninject
     2 {
     3     class Program
     4     {
     5         static void Main(string[] args)
     6         {
     7             IKernel kernel = new StandardKernel();
     8 
     9             kernel.Bind<ILogger>().To<ConsoleLogger>();
    10 
    11             ILogger logger = kernel.Get<ILogger>();
    12 
    13             logger.Log("Console log");
    14 
    15             Console.ReadKey();
    16         }
    17     }
    18 
    19     interface ILogger
    20     {
    21         void Log(string message);
    22     }
    23 
    24 
    25     class ConsoleLogger : ILogger
    26     {
    27         public void Log(string message)
    28         {
    29             Console.WriteLine("{0}: {1}", DateTime.Now, message);
    30         }
    31     }
    32 }

    2、单例范围

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

    namespace Ninject
    {
        class Program
        {
            static void Main(string[] args)
            {
                IKernel kernel = new StandardKernel();
    
                kernel.Bind<ILogger>().ToConstant(ConsoleLogger.Instance);
    
                ILogger logger = kernel.Get<ILogger>();
    
                logger.Log("Console log");
    
                Console.ReadKey();
            }
        }
    
        interface ILogger
        {
            void Log(string message);
        }
    
    
        class ConsoleLogger : ILogger
        {
            public static readonly ConsoleLogger Instance = new ConsoleLogger();
    
            private ConsoleLogger()
            {
            }
    
            public void Log(string message)
            {
                Console.WriteLine("{0}: {1}", DateTime.Now, message);
            }
        }
    }

    2)使用方法InSingletonScope:

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

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

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

    3、线程范围

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

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

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

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

    复制代码
     1 using Ninject;
     2 using NUnit.Framework;
     3 using System.Threading;
     4 
     5 namespace Demo.Ninject
     6 {
     7     [TestFixture]
     8     class NinjectTest
     9     {
    10         [Test]
    11         public void ReturnsTheSameInstancesInOneThread()
    12         {
    13             using (var kernel = new StandardKernel())
    14             {
    15                 kernel.Bind<object>().ToSelf().InThreadScope();
    16                 var instance1 = kernel.Get<object>();
    17                 var instance2 = kernel.Get<object>();
    18                 Assert.AreEqual(instance1, instance2);
    19             }
    20         }
    21 
    22         [Test]
    23         public void ReturnsDifferentInstancesInDifferentThreads()
    24         {
    25             var kernel = new StandardKernel();
    26             kernel.Bind<object>().ToSelf().InThreadScope();
    27             var instance1 = kernel.Get<object>();
    28             new Thread(() =>
    29             {
    30                 var instance2 = kernel.Get<object>();
    31                 Assert.AreNotEqual(instance1, instance2);
    32                 kernel.Dispose();
    33             }).Start();
    34         }
    35     }
    36 }
    复制代码

    第一个方法在同一个线程内请求了两个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类。

    1     class User
    2     {
    3         public string Name { get; set; }
    4         public static User Current { get; set; }
    5     }

    2)创建函数ReturnsTheSameInstancesForAUser。

    复制代码
     1         [Test]
     2         public void ReturnsTheSameInstancesForAUser()
     3         {
     4             using (var kernel = new StandardKernel())
     5             {
     6                 kernel.Bind<object>().ToSelf().InScope(ctx => User.Current);
     7                 User.Current = new User();
     8                 var instance1 = kernel.Get<object>();
     9                 User.Current.Name = "Foo";
    10                 var instance2 = kernel.Get<object>();
    11                 Assert.AreEqual(instance1, instance2);
    12             }
    13         }
    复制代码

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

    3)创建函数ReturnsDifferentInstancesForDifferentUsers。

    复制代码
     1         [Test]
     2         public void ReturnsDifferentInstancesForDifferentUsers()
     3         {
     4             using (var kernel = new StandardKernel())
     5             {
     6                 kernel.Bind<object>().ToSelf().InScope(ctx => User.Current);
     7                 User.Current = new User();
     8                 var instance1 = kernel.Get<object>();
     9                 User.Current = new User();
    10                 var instance2 = kernel.Get<object>();
    11                 Assert.AreNotEqual(instance1, instance2);
    12             }
    13         }
    复制代码

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

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

    线程范围:

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

    请求范围:

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

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

    1 var myObject = kernel.Get<MyService>();
    2 ..
    3 kernel.Release(myObject);
  • 相关阅读:
    [滤镜]的firefox兼容问题
    软件编程中的21条法则
    程序员!你应该读别人的心得,但是一定要自己注解
    致橡树——舒婷
    高级动物
    终于把网站最后一个模块了结了
    终于解决了网站程序中的问题
    北京杂种
    博客园驻小窝
    Eval函数
  • 原文地址:https://www.cnblogs.com/JustYong/p/5882416.html
Copyright © 2011-2022 走看看