简要介绍 My.Ioc 的用法
下面这段代码展示了 My.Ioc 的基本用法:
using System;
using System.Collections.Generic; namespace My.Ioc.Sample
{
public interface IConcurrency
{
int Code { get; }
} public interface IConcurrencyService
{
string Name { get; }
void AddConcurrency(IConcurrency concurrency);
void RemoveConcurrency(IConcurrency concurrency);
} public class ConcurrencyService : IConcurrencyService
{
readonly Dictionary<int, IConcurrency> _concurrencies = new Dictionary<int, IConcurrency>(); public string Name
{
get { return GetType().Name; }
} public void AddConcurrency(IConcurrency concurrency)
{
_concurrencies.Add(concurrency.Code, concurrency);
} public void RemoveConcurrency(IConcurrency concurrency)
{
_concurrencies.Remove(concurrency.Code);
}
} public class NewConcurrencyService : IConcurrencyService
{
#region IConcurrencyService Members public string Name
{
get { return GetType().Name; }
} public void AddConcurrency(IConcurrency concurrency)
{
throw new NotImplementedException();
} public void RemoveConcurrency(IConcurrency concurrency)
{
throw new NotImplementedException();
} #endregion
} public interface ISimpleConsumer
{
IConcurrencyService ConcurrencyService { get; }
} public class SimpleConsumer : ISimpleConsumer
{
readonly IConcurrencyService _concurrencyService; public SimpleConsumer(IConcurrencyService concurrencyService)
{
_concurrencyService = concurrencyService;
} public IConcurrencyService ConcurrencyService
{
get { return _concurrencyService; }
}
} public interface IComplexConsumer : IDisposable
{
IConcurrencyService ConcurrencyService { get; }
} public class ComplexConsumer : IComplexConsumer
{
readonly string _name;
readonly IConcurrencyService _concurrencyService; public ComplexConsumer(string name, IConcurrencyService concurrencyService)
{
_name = name;
_concurrencyService = concurrencyService;
} public IConcurrencyService ConcurrencyService
{
get { return _concurrencyService; }
} public string Name
{
get { return _name; }
} public string Address { get; set; } public void Print()
{
Console.WriteLine(_name + " who lives in " + (Address ?? "Fujian") + " is using the service " + _concurrencyService.Name);
} public void Dispose()
{
Console.WriteLine("ComplexConsumer is disposing...");
}
} class Program
{
static IObjectRegistration _concurrencyServiceRegistration;
static IObjectObserver<ISimpleConsumer> _simpleConsumerObserver; static void Main(string[] args)
{
// First, we need to create an instance of IObjectContainer.
IObjectContainer container = new ObjectContainer(true); // Then, we register some services
container.Register<IConcurrencyService, ConcurrencyService>()
.WhenParentTypeIsAny(typeof(SimpleConsumer), typeof(ComplexConsumer))
.In(Lifetime.Container())
.Set("ConcurrencyService")
.Return(out _concurrencyServiceRegistration); container.Register<ISimpleConsumer, SimpleConsumer>(); var consumerName = Parameter.Positional("Johnny.Liu");
container.Register<IComplexConsumer, ComplexConsumer>()
.WithConstructor(consumerName)
.WithPropertyValue("Address", "Fujian")
.WithMethod("Print")
.In(Lifetime.Transient()); // Finally, don't forget to commit the registrations to the registry.
container.CommitRegistrations(); // Now you can ask the container to build instances for you.
var simpleConsumer1 = container.Resolve<ISimpleConsumer>(); if (!container.TryGetObserver(out _simpleConsumerObserver))
throw new Exception();
_simpleConsumerObserver.Changed += OnObjectBuilderChanged;
var simpleConsumer2 = container.Resolve(_simpleConsumerObserver); using (var scope = container.BeginLifetimeScope())
{
var complexConsumer = scope.Resolve<IComplexConsumer>();
} // At last, we will unregister the current concurrency service to let the other concurrency
// service implementations to have a chance to replace it.
container.Unregister(_concurrencyServiceRegistration);
container.Register(typeof(IConcurrencyService), typeof(NewConcurrencyService));
// As we said, don't forget to commit the registrations to the registry.
container.CommitRegistrations(); using (var scope = container.BeginLifetimeScope())
{
var complexConsumer = scope.Resolve<IComplexConsumer>();
} Console.ReadLine();
} static void OnObjectBuilderChanged(ObjectBuilderChangedEventArgs args)
{
Console.WriteLine(args.ChangeMode);
}
}
}
用法比较简单,跟大家熟悉的大多数 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 的使用方法。由于篇幅的缘故,很多问题并未谈及,我们将在以后的文章中逐一向大家介绍。
简要介绍 My.Ioc 的用法的更多相关文章
- Windows ToolTips简要介绍(转)
原文转自 https://blog.csdn.net/sesiria/article/details/77450151 Windows 标准控件ToolTips简要介绍 参考文档 MSDN https ...
- 0-Broadcast机制原理简要介绍
Broadcast机制简要介绍 来源: http://blog.csdn.net/luoshengyang/article/details/6730748 导语 广播机制在Android系统中,也不算 ...
- Android Debuggerd 简要介绍和源码分析(转载)
转载: http://dylangao.com/2014/05/16/android-debuggerd-%E7%AE%80%E8%A6%81%E4%BB%8B%E7%BB%8D%E5%92%8C%E ...
- 简要介绍BASE64、MD5、SHA、HMAC几种方法。
加密解密,曾经是我一个毕业设计的重要组件.在工作了多年以后回想当时那个加密.解密算法,实在是太单纯了. 言归正传,这里我们主要描述Java已经实现的一些加密解密算法,最后介绍数字证书. ...
- [转]Android系统Surface机制的SurfaceFlinger服务简要介绍和学习计划
转自:Android系统Surface机制的SurfaceFlinger服务简要介绍和学习计划 前面我们从Android应用程序与SurfaceFlinger服务的关系出发,从侧面简单学习了Surfa ...
- [转] Android资源管理框架(Asset Manager)简要介绍和学习计划
转自:http://blog.csdn.net/luoshengyang/article/details/8738877 Android应用程序主要由两部分内容组成:代码和资源.资源主要就是指那些与U ...
- C++ Iterator迭代器介绍及Iterator迭代器用法代码举例
C++ Iterator迭代器介绍 迭代器可被用来访问一个容器类的所包函的全部元素,其行为像一个指针.举一个例子,你可用一个迭代器来实现对vector容器中所含元素的遍历.有这么几种迭代器如下: 迭代 ...
- Activity启动过程简要介绍
无论是通过点击应用程序图标来启动Activity,还是通过Activity内部调用startActivity接口来启动新的Activity,都要借助于应用程序框架层的ActivityManagerSe ...
- Android应用程序的Activity启动过程简要介绍和学习计划
文章转载至CSDN社区罗升阳的安卓之旅,原文地址:http://blog.csdn.net/luoshengyang/article/details/6685853 在Android系统中,Activ ...
随机推荐
- canvas新属性
lineCap默认值是butt,还有aquare,round 使用:context.lineCap="butt" lineJoin miter是默认 还可以是round,bevel ...
- C语言基础学习运算符-赋值运算符
简单赋值 在C语言里,运算符=并不表示相等,而是一个赋值运算符.这意味着,符号=的左边该是一个可修改的变量名,而右边是赋给该变量的值. 如下程序语句: i = i+; 在数学上,该等式无法成立.而作为 ...
- Extjs4.1.x使用Application动态按需加载MVC各模块
我们知道Extjs4之后提出了MVC模块开发,将以前肥厚的js文件拆分成小的js模块[model\view\controller\store\form\data等],通过controller拼接黏合, ...
- 001Spring4.2基本环境搭建
1:工程目录以及依赖jar包如下,如果缺少某些jar包在weblogic控制台下面会有提示 2:applicationContext.xml配置文件 <?xml version="1. ...
- Codeforces Round #312 (Div. 2)小结
爆炸了爆炸了...E题一个裸线段树没打完,A题wa了半天...... 爆炸了爆炸了....爆炸了爆炸了....rank270+滚粗 以后还是得多做模拟题...
- fastjson将bean转成字符串时首字母变小写问题
一个项目需求要求返回值为JSON格式,且大多数字段是首字母大写,还有些是类似N_TX这样的格式,在输出这样的结果时遇到了问题,由于时间紧,就直接拷贝需要的结果字段建立JavaBean类,本以为最后直接 ...
- ubuntu14.04下交叉编译器的安装
今天打算换个工作环境,在ubuntu下装交叉编译器,可谓一波三折.最后总算是装好了. 首先参照一下这位仁兄的博客http://blog.csdn.net/silleyj/article/details ...
- has-a关系——多重私有继承
#ifndef _STUDENT_H_ #define _STUDENT_H_ #include <iostream> #include <string> #include & ...
- 关于Hibernate脏检查与快照
脏检查 Session到底是如何进行脏检查的呢?当一个Customer对象被加入到Session缓存中时,Session会 为Customer对象的值类型的属性复制一份快照.当Session清理缓存时 ...
- os即时通讯客户端开发之-mac上安装MySQL
一.安装 到MySQL官网上http://dev.mysql.com/downloads/mysql/,下载mysql可安装dmg版本 比如:Mac OS X ver. 10.7 (x86, 64-b ...