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

由于上面这些限制因素,我们在 My.Ioc 中提供了 IObjectObserver/IObjectCollectionObserver 的机制。使用 IObjectObserver/IObjectCollectionObserver,我们可以实现针对特定契约类型 (Contract Type) 的更加高效和实时的侦听。

在这两者中,IObjectObserver 侦听的是一个实现了某个契约的服务,而 IObjectCollectionObserver 侦听的则是一组实现了相同契约的服务。下面我们通过代码示例来了解它们的用法:

using System;
using System.Collections.Generic;
using My.Ioc; namespace ObserverUsage
{
#region ObjectObserver Types public class ServiceConsumer
{
Service _service; public ServiceConsumer(Service service)
{
_service = service;
}
} public class Service
{
} #endregion #region ObjectCollectionObserver Types public class Tree
{
readonly IList<Node> _childNodes; public Tree(IList<Node> childNodes)
{
_childNodes = new List<Node>(childNodes);
} public IList<Node> ChildNodes
{
get { return _childNodes; }
}
} public abstract class Node
{
string _name; public string Name
{
get
{
_name = _name ?? GetType().Name;
return _name;
}
}
} public class Node1 : Node
{
} public class Node2 : Node
{
} public class Node3 : Node
{
} public class Node4 : Node
{
} #endregion class Program
{
private static IObjectContainer _container; static void Main(string[] args)
{
_container = new ObjectContainer(false);
RunObjectObserverTest();
RunObjectCollectionObserverTest(); Console.ReadLine();
} #region ObjectObserver static void RunObjectObserverTest()
{
IObjectRegistration<Service> serviceRegistration;
IObjectObserver<ServiceConsumer> consumerObserver;
IObjectObserver<Service> serviceObserver; // Register and commit
_container.Register<Service>().Return(out serviceRegistration);
_container.Register<ServiceConsumer>();
_container.CommitRegistrations(); // Try to get the ObjectObserver and hook events
if (_container.TryGetObserver(out serviceObserver))
serviceObserver.Changed += OnObjectBuilderChangedForService;
if (_container.TryGetObserver(out consumerObserver))
consumerObserver.Changed += OnObjectBuilderChangedForConsumer; // Try to resolve an instance of ServiceConsumer to build the relationship between the
// ServiceConsumer and Service, so that if we unregistered the Service, not only the
// service observer, but also the consumer observer, will receive the notification.
var consumer = _container.Resolve<ServiceConsumer>(); // Unregister the Service. The observers should receive the notification later.
_container.Unregister(serviceRegistration); // Dispose the observers
consumerObserver.Dispose();
serviceObserver.Dispose();
} static void OnObjectBuilderChangedForService(ObjectBuilderChangedEventArgs args)
{
if (args.ChangeMode == ObjectBuilderChangeMode.Activate)
Console.WriteLine("The Service is activated...");
else if (args.ChangeMode == ObjectBuilderChangeMode.Deactivate)
Console.WriteLine("The Service is deactivated...");
} static void OnObjectBuilderChangedForConsumer(ObjectBuilderChangedEventArgs args)
{
if (args.ChangeMode == ObjectBuilderChangeMode.Activate)
Console.WriteLine("The ServiceConsumer is activated...");
else if (args.ChangeMode == ObjectBuilderChangeMode.Deactivate)
Console.WriteLine("The ServiceConsumer is deactivated...");
} #endregion #region ObjectCollectionObserver private static Tree _tree; static void RunObjectCollectionObserverTest()
{
IObjectRegistration<Node> nodeRegistration;
IObjectCollectionObserver<Node> nodesObserver; // Register and commit
_container.Register<Node, Node1>().Return(out nodeRegistration);
_container.Register<Node, Node2>();
_container.Register<Node, Node3>();
_container.Register<Node, Node4>();
_container.CommitRegistrations(); // Try to get the ObjectObserver and hook events
if (_container.TryGetObserver(out nodesObserver))
nodesObserver.Changed += OnObjectBuilderChangedForNodeCollection; var nodes = _container.ResolveAll(nodesObserver);
_tree = new Tree(nodes);
PrintTree(); // Unregister the Service. The observers should receive the notification later.
_container.Unregister(nodeRegistration);
PrintTree(); _container.Register<Node, Node1>();
_container.CommitRegistrations();
PrintTree(); // Dispose the observer
nodesObserver.Dispose();
} static void PrintTree()
{
Console.WriteLine();
foreach (var node in _tree.ChildNodes)
Console.WriteLine(node.Name);
} static void OnObjectBuilderChangedForNodeCollection(ObjectBuilderCollectionChangedEventArgs args)
{
if (args.ChangeMode == ObjectBuilderCollectionChangeMode.Add)
{
var node = (Node)_container.Resolve(args.ObjectBuilder, null);
_tree.ChildNodes.Add(node);
}
else if (args.ChangeMode == ObjectBuilderCollectionChangeMode.Remove)
{
_tree.ChildNodes.RemoveAt(args.Position);
}
} #endregion
}
}

在上述示例中,我们简单演示了 IObjectObserver/IObjectCollectionObserver 的使用方法。

恰如您在示例中看到的,使用 IObjectObserver,当服务停用(注销)/激活(注册)时,该服务的观察者 (Observer) 以及任何依赖于该服务的上层服务的观察者都会收到通知,而我们可以于此时在处理程序中执行一些操作,从而更好地响应服务变化。

与 IObjectObserver 相比,IObjectCollectionObserver 的用法略有一点不同,因为它侦听的是一组而不是一个服务。使用 IObjectCollectionObserver 时,当某个服务注册/注销时,如果该服务或者它的任何上层服务处于 IObjectCollectionObserver 的侦听之中,IObjectCollectionObserver 便会发出通知,这样我们就会获知位于集合中哪个位置 (Position) 的服务被停用(注销)/激活(注册)的信息,从而可以根据此通知信息在处理程序中执行相应的操作,以更新(删除/添加)服务集合(示例中的节点树)

本文源码可从此处下载。

My.Ioc 代码示例——使用观察者机制捕获注册项状态的变化的更多相关文章

  1. My.Ioc 代码示例——如何使用默认构造参数,以及如何覆盖默认构造参数

    在 Ioc 世界中,有些框架(例如 Autofac/NInject/Unity)支持传递默认参数,有些框架(例如 SimpleInjector/LightInjector 等)则不支持.作为 My.I ...

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

    装饰器模式体现了一种“组合优于继承”的思想.当我们要动态为对象增加新功能时,装饰器模式往往是我们的好帮手. 很多后期出现的 Ioc 容器都为装饰器模式提供了支持,比如说 Autofac.在 My.Io ...

  3. My.Ioc 代码示例——实现自动注册/解析

    在很多 Ioc 容器中,当使用者向容器请求实现了某个契约类型 (Contract Type) 的服务时 (调用类似如下方法 container.Resolve(Type contractType)), ...

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

    本文旨在通过创建一棵插件树来演示条件绑定和元数据的用法. 说“插件树”也许不大妥当,因为在一般观念中,谈到插件树,我们很容易会想到 Winform/Wpf 中的菜单.举例来说,如果要在 Winform ...

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

    当您需要从 Ioc 容器中注销/删除一个注册项的时候,您会怎么做呢? 有人曾经在 stackoverflow 上提问“如何从 Unity 中注销一个注册项”.对于这个问题,有人的回答是“有趣.你为什么 ...

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

    在使用 Ioc 框架时,一般我们建议集中在一个称为 Composition Root(其含义请参见下面的小注)的位置来注册 (Register) 和解析 (Resolve) 服务.这种做法的目的在于限 ...

  7. My.Ioc 代码示例——属性和方法注入

    在 My.Ioc 中,我们可以指定让容器在构建好对象实例之后,自动为我们调用对象的公共方法或是为对象的公共属性赋值.在解析对象实例时,容器将根据我们在注册对象时指定的方法调用或属性赋值的先后顺序,调用 ...

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

    很多 Ioc 框架在创建对象的过程中,都会采取某种方式来缓存/复用/释放已构建的对象.在 My.Ioc 中,这个目的是通过 Lifetime/ILifetimeScope 来实现的.其中,Lifeti ...

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

    本文的目的在于通过一些示例,向大家说明 My.Ioc 支持哪些类型的依赖关系.也就是说,如何设计对象不会导致循环依赖. 在 Ioc 世界中,循环依赖是一个顽敌.这不仅因为它会导致 Ioc 容器抛出异常 ...

随机推荐

  1. GNU FORK PTHREAD SIGNALS

    Linux程序设计入门 - fork, pthread, and signals 在UNIX程序设计中,学会fork及signal的运用,算是相当基本的功夫. fork()及signal经常运用在da ...

  2. BZOJ 1263 整数划分

    Description 从文件中读入一个正整数\(n\).要求将\(n\)写成若干个正整数之和,并且使这些正整数的乘积最大. 例如,\(n=13\),则当\(n\)表示为\(4+3+3+3\)(或\( ...

  3. [BZOJ 1816] [Cqoi2010] 扑克牌 【二分答案】

    题目链接:BZOJ - 1816 题目分析 答案具有可以二分的性质,所以可以二分答案. 验证一个答案 x 是否可行,就累加一下各种牌相对于 x 还缺少的量,如果总和超过了 x 或 m ,就不可行. 因 ...

  4. 教你在Java的普通类中轻松获取Session以及request中保存的值

    曾经有多少人因为不知如何在业务类中获取自己在Action或页面上保存在Session中值,当然也包括我,但是本人已经学到一种办法可以解决这个问题,来分享下,希望对你有多多少少的帮助! 如何在Java的 ...

  5. JavaScript API

    HTML5 DOM, BOM, XMLHttpRequest, NodeJS, Framework Framework---------------> jQuery zepto Undersco ...

  6. 如何开发Android Wear应用程序

    Android Wear是连接安卓手机和可穿戴产品的一个平台.自从今年上半年发布以来,Android Wear获得了大量关注,既有来自消费者的关注,也有来自开发商的关注,后者希望自己的应用程序已经准备 ...

  7. SVN服务器搭建(与apache整合)

    一.SVN介绍 SVN是一个版本控制工具,Subversion的版本库(repository),就是位于服务器,统一管理和储存数据的地方. 二.SVN数据存储方式 在Subversion中,版本库的数 ...

  8. 字符串(后缀自动机):NOI 2016 优秀的拆分

    [问题描述] 如果一个字符串可以被拆分为 AABB 的形式,其中 A 和 B 是任意非空字符串, 则我们称该字符串的这种拆分是优秀的. 例如,对于字符串 aabaabaa,如果令 A = aab, B ...

  9. 【模拟】NEERC15 G Generators(2015-2016 ACM-ICPC)(Codeforces GYM 100851)

    题目链接: http://codeforces.com/gym/100851 题目大意: n个序列.每个序列有4个值x,a,b,c,之后按照x=(a*x+b)%c扩展无穷项. 求每个序列各取一个数之后 ...

  10. 如果在安装32位oracle 客户端组件时的情况下以64位模式运行,将出现问题

    今天要写个程序,环境是win7+ vs2008+ oracle.首先得保证能连接到数据库.确认代码是没有问题的,但是拿过来直接.报错: “尝试加载 Oracle 客户端库时引发 BadImageFor ...