简要介绍 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 ...
随机推荐
- oracle常用SQL总结
这里我们介绍的是 40+ 个非常有用的 Oracle 查询语句,主要涵盖了日期操作,获取服务器信息,获取执行状态,计算数据库大小等等方面的查询.这些是所有 Oracle 开发者都必备的技能,所以快快收 ...
- 【新手--android日记】实现IOS风格电话界面
[前言--新手日记] 开始学习android开发,通过做一个通讯录练习,打算实现各种自己想实现的功能. 新手作品,技术含量很浅.主要是记录自己的学习过程. 纯学习之用,求评论,求建议,求教导. [正题 ...
- Swift互用性:与 C的API交互(Swift 2.0版)-b
节包含内容: 基本数据类型(Primitive Types) 枚举(Enumerations) 指针(Pointer) 全局常量(Global Constants) 预处理指令(Preprocesso ...
- kd树的构建以及搜索
构建算法 k-d树是一个二叉树,每个节点表示一个空间范围.表1给出的是k-d树每个节点中主要包含的数据结构. 表1 k-d树中每个节点的数据类型 域名 数据类型 描述 Node-data 数据矢量 数 ...
- UPdate 延时盲注之小技巧
Title:UPdate 延时盲注之小技巧 --2014-06-05 15:21 UPDATE TABLEZZZ SET zz=111111 where id=$id 当TABLEZZZ表为空的时候 ...
- new Random().nextInt
public static void main(String[] args) { System.out.println(new Random().nextInt(0)); } Exception in ...
- POJ2251 Dungeon Master(bfs)
题目链接. 题目大意: 三维迷宫,搜索从s到e的最小步骤数. 分析: #include <iostream> #include <cstdio> #include <cs ...
- COJN 0584 800603吃糖果
800603吃糖果 难度级别:B: 运行时间限制:1000ms: 运行空间限制:51200KB: 代码长度限制:2000000B 试题描述 名名的妈妈从外地出差回来,带了一盒好吃又精美的巧克力给名名( ...
- Bit,Bytes,KB,MB,GB,TB,PB,EB,ZB,YB
Bit,Bytes,KB,MB,GB,TB,PB,EB,ZB,YB 汉字字符 2字节英文字符 1字节中文标点 2字节英文标点 1字节一个字节就是一个八位二进制数啊,2就是00000010,4就是000 ...
- yui datatable动态修改行号
相关函数 getRecord :YAHOO.widget.Record getRecord ( row ) For the given identifier, returns the associa ...