My.Ioc 代码示例——利用 ObjectBuilderRequested 事件实现延迟注册

在使用 Ioc 框架时,一般我们建议集中在一个称为 Composition Root(其含义请参见下面的小注)的位置来注册 (Register) 和解析 (Resolve) 服务。该做法的目的在于通过限制 Ioc 的使用场合,尽量减少应用程序本身对于 Ioc 框架的依赖。

这种模式固然能够很好地解耦应用程序和 Ioc 框架,使我们能够在需要的时候方便地更换 Ioc 框架,但它同时也带来了一个问题:难道我们一定要在程序启动时注册所有服务吗?有些服务并不一定会马上用到,有一些服务甚至可能不会用到。在这种情况下,如果仍然按照上述模式,在程序启动时将所有服务统统注册到容器中,结果无疑会减缓程序的启动速度,同时会加大内存消耗。

针对这个问题,我们在 My.Ioc 中给出了延迟注册的解决办法。它的原理其实很简单:当应用程序向 My.Ioc 容器请求某个服务时,如果此时该服务尚未注册,容器便会触发一个 ObjectBuilderRequested 事件,并在事件参数中提供所请求的契约类型 (Contract Type) 和注入点信息 (InjectionInfo),而订阅了该事件的处理程序 (Event Handler) 便可以在这个时候根据契约类型和注入点信息来决定是否向容器中注册相应的服务以满足应用程序需求。

用法很简单,示例代码如下:

using System;
using System.Diagnostics;
using My.Ioc;

namespace LazyRegistration
{
    public interface ILazyService
    { }
    public class LazyService : ILazyService
    { }

    class Program
    {
        static bool _eventHandled = false;

        static void Main(string[] args)
        {
            IObjectContainer container = new ObjectContainer(false);
            container.ObjectBuilderRequested += OnObjectBuilderRequested;
            var lazy = container.Resolve<ILazyService>();
            Debug.Assert(lazy != null);
            Debug.Assert(lazy is LazyService);

            Console.WriteLine(_eventHandled);
            Console.ReadLine();
        }

        static void OnObjectBuilderRequested(ObjectBuilderRequestedEventArgs args)
        {
            if (args.ContractType == typeof (ILazyService))
            {
                args.Register<ILazyService, LazyService>();
                _eventHandled = true;
            }
        }
    }
}

 小注:

Composition Root 的定义是“一个组合应用程序各个模块的位置,一个应用程序中应该仅有一个这样的位置,这个位置通常是应用程序的入口点。例如,对于控制台应用程序来说,这个位置就是 Main 函数;对于 ASP.NET MVC 应用程序来说,这个位置可能是 global.asax;对于 WPF 应用程序来说,这个位置是 Application.OnStartup 方法...”。

源码可从此处下载。

时间: 2024-10-13 23:22:58

My.Ioc 代码示例——利用 ObjectBuilderRequested 事件实现延迟注册的相关文章

My.Ioc 代码示例——使用默认构造参数和覆盖参数

在 Ioc 世界中,有些框架(例如 Autofac/NInject/Unity)支持传递默认参数,有些框架(例如 SimpleInjector/LightInjector 等)则不支持.作为 My.Ioc 来说,我们支持默认参数. 当我们在 My.Ioc 中注册对象时,有些对象类型 (System.Type) 要求我们必须提供默认参数,而有些则不是必要的.在 My.Ioc 中,默认参数有两个作用:1. 容器根据默认参数来选择用于构建对象的构造函数.而一旦选定构造函数之后,今后容器便会一直使用该构

My.Ioc 代码示例——使用 Observer 机制捕获注册项 (Registration) 状态的变化

在 My.Ioc 中,要想在服务注销/注册时获得通知,可以通过订阅 ObjectBuilderRegistered 和 ObjectBuilderUnregistering 这两个事件来实现.但是,使用这两个事件也有一些不足.首先,它们只能针对当前注册/注销的服务发出通知,而对于依赖当前服务的上层服务的激活/停用事件(由于当前服务的注册/注销而引起的),它们则无能为力:其次,这两者都是针对所有注册项的广播事件.也就是说,只要发生注册/注销,无论注册/注销的是什么服务,容器都会向所有订阅了这两个事

My.Ioc 代码示例——Lifetime 和 ILifetimeScope

很多 Ioc 框架在创建对象的过程中,都会采取某种方式来缓存/复用/释放已构建的对象.在 My.Ioc 中,这个目的是通过 Lifetime/ILifetimeScope 来实现的.其中,Lifetime 实现了缓存/复用对象的功能,ILifetimeScope 则实现了复用/释放对象的功能. My.Ioc 默认提供了三种 Lifetime:ContainerLifetime.TransientLifetime 和 ScopeLifetime.这里简单解释一下它们的含义:ContainerLif

My.Ioc 代码示例——避免循环依赖

本文的目的在于通过一些示例,向用户说明 My.Ioc 支持哪些类型的依赖关系.也就是说,如何设计对象不会导致循环依赖. 在 Ioc 世界中,循环依赖是一个顽敌.这不仅因为它会导致 Ioc 容器抛出异常,而且还因为它是不可预知的,尽管通过仔细的配置是可以尽量避免这个问题的. 当用户在 Ioc 容器中注册对象时,他们事先并不知道该对象与其他对象之间的依赖关系,因为依赖关系是由 Ioc 容器管理的.这种依赖关系要等到用户首次调用 container.Resolve(contractType) 时才能确

My.Ioc 代码示例——谈一谈如何实现装饰器 (Decorator) 模式,兼谈如何扩展 My.Ioc

装饰器模式体现了一种“组合优于继承”的思想.当我们要动态为对象增加新功能时,装饰器模式往往是我们的好帮手. 很多后期出现的 Ioc 容器都为装饰器模式提供了支持,比如说 Autofac.在 My.Ioc 中,默认不提供装饰器支持,但我们可以自己进行扩展,以提供此项功能. using System; using System.Collections.Generic; using System.Diagnostics; using System.Reflection; using My.Ioc; u

My.Ioc 代码示例——注册项 (Registration) 的注销和更新

当您需要从 Ioc 容器中注销/删除一个注册项的时候,您会怎么做呢? 有人曾经在 stackoverflow 上提问“如何从 Unity 中注销一个注册项”,对于这个问题,有人的回答是“有趣.你为什么要这样做?”,也有人提出了一些变通的解决办法,例如通过自定义 LifetimeManager 来实现等等.这些其实都不是根本的解决办法.因为服务的注册/注销本身是一个容器级过程,当中一定会涉及到一些中间对象的创建/清理 (Dispose) 以及不同对象之间的协调,本应由容器来提供支持才对. 遗憾的是

My.Ioc 代码示例——使用条件绑定和元数据(可选)构建插件树

本文的目的在于通过创建一棵插件树来演示条件绑定和元数据的用法. 说“插件树”也许是不大妥当的,因为在一般观念中,谈到插件树,我们很容易会想到 Winform/Wpf 中的菜单.举例来说,如果要在 Winform 中创建一个菜单,我们使用类似如下代码: // Create File menu var newMenu = new ToolStripMenuItem(); var localProjectMenu = new ToolStripMenuItem(); var remoteProject

JDK7新特性详细说明及代码示例

在2011年7月28日,Oracle发布了JDK7的正式版.最近我从网上搜集了一些资料,把文字说明和代码示例结合起来,方便我们的学习. 下面我们来看看JDK7比6多了哪些新特性 1.访问文件系统 与之前的JDK中通过java.io.File访问文件的方式不同,JDK7将通过java.nio.file包中的类完成.JDK7会使用java.nio.file.Path类来操作任何文件系统中的文件.(这里说的任何文件系统指的是可以使用任何文件存储方式的文件系统) 示例: Java7之前 File fil

JAVA NIO工作原理及代码示例

简介:本文主要介绍了JAVA NIO中的Buffer, Channel, Selector的工作原理以及使用它们的若干注意事项,最后是利用它们实现服务器和客户端通信的代码实例. 欢迎探讨,如有错误敬请指正 如需转载,请注明出处 http://www.cnblogs.com/nullzx/ 1. ByteBuffer 1.1直接缓冲区和非直接缓冲区 下面是创建ByteBuffer对象的几种方式 static ByteBuffer allocate(int capacity) static Byte