zoukankan      html  css  js  c++  java
  • 简要介绍 My.Ioc 的用法

    下面这段代码展示了 My.Ioc 的基本用法:

      1 using System;
      2 using System.Collections.Generic;
      3 
      4 namespace My.Ioc.Sample
      5 {
      6     public interface IConcurrency
      7     {
      8         int Code { get; }
      9     }
     10 
     11     public interface IConcurrencyService
     12     {
     13         string Name { get; }
     14         void AddConcurrency(IConcurrency concurrency);
     15         void RemoveConcurrency(IConcurrency concurrency);
     16     }
     17 
     18     public class ConcurrencyService : IConcurrencyService
     19     {
     20         readonly Dictionary<int, IConcurrency> _concurrencies = new Dictionary<int, IConcurrency>();
     21 
     22         public string Name
     23         {
     24             get { return GetType().Name; }
     25         }
     26 
     27         public void AddConcurrency(IConcurrency concurrency)
     28         {
     29             _concurrencies.Add(concurrency.Code, concurrency);
     30         }
     31 
     32         public void RemoveConcurrency(IConcurrency concurrency)
     33         {
     34             _concurrencies.Remove(concurrency.Code);
     35         }
     36     }
     37 
     38     public class NewConcurrencyService : IConcurrencyService
     39     {
     40         #region IConcurrencyService Members
     41 
     42         public string Name
     43         {
     44             get { return GetType().Name; }
     45         }
     46 
     47         public void AddConcurrency(IConcurrency concurrency)
     48         {
     49             throw new NotImplementedException();
     50         }
     51 
     52         public void RemoveConcurrency(IConcurrency concurrency)
     53         {
     54             throw new NotImplementedException();
     55         }
     56 
     57         #endregion
     58     }
     59 
     60     public interface ISimpleConsumer
     61     {
     62         IConcurrencyService ConcurrencyService { get; }
     63     }
     64 
     65     public class SimpleConsumer : ISimpleConsumer
     66     {
     67         readonly IConcurrencyService _concurrencyService;
     68 
     69         public SimpleConsumer(IConcurrencyService concurrencyService)
     70         {
     71             _concurrencyService = concurrencyService;
     72         }
     73 
     74         public IConcurrencyService ConcurrencyService
     75         {
     76             get { return _concurrencyService; }
     77         }
     78     }
     79 
     80     public interface IComplexConsumer : IDisposable
     81     {
     82         IConcurrencyService ConcurrencyService { get; }
     83     }
     84 
     85     public class ComplexConsumer : IComplexConsumer
     86     {
     87         readonly string _name;
     88         readonly IConcurrencyService _concurrencyService;
     89 
     90         public ComplexConsumer(string name, IConcurrencyService concurrencyService)
     91         {
     92             _name = name;
     93             _concurrencyService = concurrencyService;
     94         }
     95 
     96         public IConcurrencyService ConcurrencyService
     97         {
     98             get { return _concurrencyService; }
     99         }
    100 
    101         public string Name
    102         {
    103             get { return _name; }
    104         }
    105 
    106         public string Address { get; set; }
    107 
    108         public void Print()
    109         {
    110             Console.WriteLine(_name + " who lives in " + (Address ?? "Fujian") + " is using the service " + _concurrencyService.Name);
    111         }
    112 
    113         public void Dispose()
    114         {
    115             Console.WriteLine("ComplexConsumer is disposing...");
    116         }
    117     }
    118 
    119     class Program
    120     {
    121         static IObjectRegistration _concurrencyServiceRegistration;
    122         static IObjectObserver<ISimpleConsumer> _simpleConsumerObserver;
    123 
    124         static void Main(string[] args)
    125         {
    126             // First, we need to create an instance of IObjectContainer.
    127             IObjectContainer container = new ObjectContainer(true);
    128 
    129             // Then, we register some services
    130             container.Register<IConcurrencyService, ConcurrencyService>()
    131                 .WhenParentTypeIsAny(typeof(SimpleConsumer), typeof(ComplexConsumer))
    132                 .In(Lifetime.Container())
    133                 .Set("ConcurrencyService")
    134                 .Return(out _concurrencyServiceRegistration);
    135 
    136             container.Register<ISimpleConsumer, SimpleConsumer>();
    137 
    138             var consumerName = Parameter.Positional("Johnny.Liu");
    139             container.Register<IComplexConsumer, ComplexConsumer>()
    140                 .WithConstructor(consumerName)
    141                 .WithPropertyValue("Address", "Fujian")
    142                 .WithMethod("Print")
    143                 .In(Lifetime.Transient());
    144 
    145             // Finally, don't forget to commit the registrations to the registry.
    146             container.CommitRegistrations();
    147 
    148             // Now you can ask the container to build instances for you.
    149             var simpleConsumer1 = container.Resolve<ISimpleConsumer>();
    150 
    151             if (!container.TryGetObserver(out _simpleConsumerObserver))
    152                 throw new Exception();
    153             _simpleConsumerObserver.Changed += OnObjectBuilderChanged;
    154             var simpleConsumer2 = container.Resolve(_simpleConsumerObserver);
    155 
    156             using (var scope = container.BeginLifetimeScope())
    157             {
    158                 var complexConsumer = scope.Resolve<IComplexConsumer>();
    159             }
    160 
    161             // At last, we will unregister the current concurrency service to let the other concurrency 
    162             // service implementations to have a chance to replace it.
    163             container.Unregister(_concurrencyServiceRegistration);
    164             container.Register(typeof(IConcurrencyService), typeof(NewConcurrencyService));
    165             // As we said, don't forget to commit the registrations to the registry.
    166             container.CommitRegistrations();
    167 
    168             using (var scope = container.BeginLifetimeScope())
    169             {
    170                 var complexConsumer = scope.Resolve<IComplexConsumer>();
    171             }
    172 
    173             Console.ReadLine();
    174         }
    175 
    176         static void OnObjectBuilderChanged(ObjectBuilderChangedEventArgs args)
    177         {
    178             Console.WriteLine(args.ChangeMode);
    179         }
    180     }
    181 }
    View Code

    用法比较简单,跟大家熟悉的大多数 Ioc 容器差不多。我们这里来逐句解释一下:

    IObjectContainer container = new ObjectContainer(true);

    这一句创建了一个 ObjectContainer 对象。构造参数 true 表示容器默认将采用 Emit(动态生成代码)方式来构建对象。

    container.Register<IConcurrencyService, ConcurrencyService>()
                    .WhenParentTypeIsAny(typeof(SimpleConsumer), typeof(ComplexConsumer))
                    .In(Lifetime.Container())
                    .Set("ConcurrencyService")
                    .Return(out _concurrencyServiceRegistration);

    Register 方法将一个 ConcurrencyService 实现绑定到 IConcurrencyService 契约。WhenParentTypeIsAny 方法指定该服务只能用于 SimpleConsumer 或 ComplexConsumer 类。因此,如果您稍后在解析时写上以下这句:

    var concurrencyService = container.Resolve<IConcurrencyService>();

    则会收到一个 InvalidObjectBuilderException 错误,因为我们在上面的配置中已经指定了 IConcurrencyService 这个服务只能在构造 SimpleConsumer 或 ComplexConsumer 实例时由相应的 ObjectBuilder 向容器请求。

    In 方法指定该服务注册项的生命周期,这里使用的是 Container 生命周期,即注册项的生命周期将同容器一样长,而且每次向容器请求该服务时,返回的都是相同的实例。也就是说,这是一个单例对象。Set 方法表明附加一个元数据 ("ConcurrencyService") 到该服务注册项中。Return 方法返回一个 IObjectRegistration 对象。该对象可以作为一个存根,用于在不再需要该服务的时候注销该服务。同时,它也可用于解析服务对象(调用 container.Resolve(IObjectRegistration registration) 方法重载),而不必像调用 container.Resolve(Type contractType) 时一样每次都从注册表中检索服务。

    var consumerName = Parameter.Positional("Johnny.Liu");
    container.Register<IComplexConsumer, ComplexConsumer>()
        .WithConstructor(consumerName)
        .WithPropertyValue("Address", "Fujian")
        .WithMethod("Print")
        .In(Lifetime.Transient());

    上面这句代码指定将 ComplexConsumer 绑定到 IComplexConsumer,同时我们注意到这里还提供了一个默认构造参数。在这里,这个构造参数是必需的,因为 ComplexConsumer 构造函数的签名是:

    public ComplexConsumer(string name, IConcurrencyService concurrencyService)

    我们看到这个构造函数的第一个参数是 string 类型,在 My.Ioc 中这种类型的参数是不可自动装配的 (non-autowirable),用户必须为不可自动装配的依赖项提供一个默认值(不可自动装配的类型包括:所有值类型 + string + Type)。

    WithPropertyValue 方法和 WithMethod 方法告诉容器,在构建好 ComplexConsumer 对象后,立即将该对象的 Address 属性赋值为“Fujian”,并调用该对象的“Print”方法。

    配置(注册)好所有服务之后,此时这些服务并没有添加到注册表,而是被缓存到一个 RegistrationCommitter 中,因此我们需要显式调用下面这句代码将所有注册项提交到注册表中:

    container.CommitRegistrations();

    经过上面的配置,我们终于可以让容器为我们构建对象实例了。

    var simpleConsumer1 = container.Resolve<ISimpleConsumer>();

    这句正是向容器请求返回一个实现 ISimpleConsumer 接口的对象。

    除了直接向容器请求对象之外,我们还可以向容器请求返回一个 IObjectObserver/IObjectCollectionObserver 对象,并通过该对象来解析服务实例,如下所示:

    if (!container.TryGetObserver(out _simpleConsumerObserver))
        throw new Exception();
    _simpleConsumerObserver.Changed += OnObjectBuilderChanged;
    var simpleConsumer2 = container.Resolve(_simpleConsumerObserver);

    这样做的好处是,当该对象 (SimpleConsumer) 依赖的其他子对象(这里是 IConcurrencyService 对象)注册/注销/激活/停用时, Observer 对象将会收到通知(需要订阅该 Observer 对象的 Changed 事件)。此外,IObjectObserver 和 IObjectCollectionObserver 对象与 IObjectRegistration 对象一样,也可以直接用于解析服务对象,而不必每次都向注册表检索服务,从而可以提高性能。

    IComplexConsumer 对象的解析与 ISimpleConsumer 有点不一样,我们看下面这段代码:

    using (var scope = container.BeginLifetimeScope())
    {
        var complexConsumer = scope.Resolve<IComplexConsumer>();
    }

    这里,我们首先向容器请求获取一个 ILifetimeScope 对象,然后使用该对象来解析 IComplexConsumer 对象。这是因为 IComplexConsumer 实现了 IDisposable 接口,这表明该对象在使用完之后需要清理资源。在 My.Ioc 框架中,解析任何实现了 IDisposable 接口的对象时都需要先申请一个 ILifetimeScope,因为对象资源的清理是通过 ILifetimeScope 来完成的。ILifetimeScope 类似于我们通常所说的“变量作用域”的概念,但它还实现了对象共享的功能,关于这个话题我们还会在以后的文章中加以介绍,这里不再赘言。

    使用完毕之后,我们可以将不再需要的服务注册项注销,如下所示:

    container.Unregister(_concurrencyServiceRegistration);

    运行这句之后,_simpleConsumerObserver 将被停用,而无法再用于解析服务对象,因为其依赖的服务 (IConcurrencyService) 已被注销。同时 OnObjectBuilderChanged 方法也会收到相应通知。不仅 ISimpleConsumer,此时所有直接和间接依赖于 IConcurrencyService 的服务都将被停用,而无法用于解析服务对象。如果我们想要让这些服务再次恢复功能,可以再注册一个实现了 IConcurrencyService 契约的服务并将其注册到容器中,如下代码所示:

    container.Register(typeof(IConcurrencyService), typeof(NewConcurrencyService));
    container.CommitRegistrations();

    这样,那些依赖于 IConcurrencyService 契约的服务都将恢复功能。我们来再次运行下面的代码看一看:

    using (var scope = container.BeginLifetimeScope())
    {
        var complexConsumer = scope.Resolve<IComplexConsumer>();
    }

    如无意外,运行上面这段代码,控制台将会输出:

    "Johnny.Liu who lives in Fujian is using the service NewConcurrencyService"
    "ComplexConsumer is disposing..."

    表明我们的新 NewConcurrencyService 服务已取代了原来的 ConcurrencyService 并正常工作,且 ComplexConsumer 对象在超出作用域后已被清理。

    总结

    上面,我们简单地介绍了 My.Ioc 的使用方法。由于篇幅的缘故,很多问题并未谈及,我们将在以后的文章中逐一向大家介绍。

  • 相关阅读:
    linux服务器安全配置攻略
    Linux服务器调优
    Tengine + Lua + GraphicsMagick 实现图片自动裁剪/缩放
    nginx缓存设置
    动态缓存技术之CSI,SSI,ESI
    ionic环境配置
    Node.js企业开发:应用场景
    HashMap实现原理、核心概念、关键问题的总结
    《Windows核心编程》读书笔记.Chapter06线程基础
    开发环境eclipse for Mac 下的常用快捷键汇总(基本参照Win系,将Ctrl换为Command)
  • 原文地址:https://www.cnblogs.com/johnny-liu/p/3953411.html
Copyright © 2011-2022 走看看