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

本文的目的在于通过一些示例,向大家说明 My.Ioc 支持哪些类型的依赖关系。也就是说,如何设计对象不会导致循环依赖。

在 Ioc 世界中,循环依赖是一个顽敌。这不仅因为它会导致 Ioc 容器抛出异常,而且还因为它是不可预知的,尽管通过仔细的配置是可以尽量避免这个问题的。

当我们在 Ioc 容器中注册对象时,我们事先并不知道该对象与其他对象之间的依赖关系,因为依赖关系是由 Ioc 容器管理的。这种依赖关系要等到我们首次调用 container.Resolve(contractType) 时才能确定。而且,它还有可能会随着所依赖对象的注册/注销而发生变化。

因此,要想避免循环依赖问题,那么在设计对象时,仔细地思考该对象与其他对象之间的依赖关系,审慎地区分不同对象的职责就显得比较重要了。当然,对象设计是 Ioc 容器之外的事情了,我们没有办法加以约束。但是,即使您不使用 Ioc 容器,对象设计也是一个值得您深思熟虑的大问题。而一旦您选择使用 Ioc,那也意味着您的对象设计需要更多围绕 Ioc 来考虑。

其实,在 My.Ioc 中要想避免循环依赖也很简单,只要遵循一个原则即可,那就是 [不要在对象构造过程中引入循环依赖]。下面我们结合示例代码来讲解。

using System;
using System.Diagnostics;
using My.Ioc;
using My.Ioc.Exceptions;namespace HowToAvoidCyclicDependency
{#region Test clazz#region Case 3public class Grade3{private readonly Room3 _room;public Grade3(Room3 room){_room = room;}public Room3 Room{get { return _room; }}}public class Room3{public Grade3 Grade { get; set; }}#endregion#region Case 2public class Grade2{private readonly Room2 _room;public Grade2(Room2 room){_room = room;room.Grade = this;}public Room2 Room{get { return _room; }}}public class Room2{public Grade2 Grade { get; set; }}#endregion#region Case 1public class Grade1{public Room1 Room { get; set; }}public class Room1{public Grade1 Grade { get; set; }}#endregion#endregionclass Program{static void Main(string[] args){var container = new ObjectContainer(false);Register(container);Resolve(container);Console.WriteLine("HowToAvoidCyclicDependency success...");Console.ReadLine();}static void Register(IObjectContainer container){container.Register<Grade3>().In(Lifetime.Transient());container.Register<Room3>().WithPropertyAutowired("Grade").In(Lifetime.Transient());container.Register<Grade2>().In(Lifetime.Transient());container.Register<Room2>().In(Lifetime.Transient());container.Register<Grade1>().WithPropertyAutowired("Room").In(Lifetime.Transient());container.Register<Room1>().WithPropertyAutowired("Grade").In(Lifetime.Transient());container.CommitRegistrations();}static void Resolve(IObjectContainer container){var grade1 = container.Resolve<Grade1>();Debug.Assert(grade1 == grade1.Room.Grade);var room1 = container.Resolve<Room2>();Debug.Assert(room1 == room1.Grade.Room);// No cyclic dependency in constructorvar grade2 = container.Resolve<Grade2>();Debug.Assert(grade2 == grade2.Room.Grade);try{// Cyclic dependency in constructor// The call path is: Grade => Room => Gradevar grade3 = container.Resolve<Grade3>();}catch (Exception ex){Debug.Assert(ex is CyclicDependencyException);}}}
}
View Code

在示例代码中,我们设计了三对 Grade/Room 类,用来演示三种不同的情况。

先来看 Grade1/Room1。

public class Grade1
{public Room1 Room { get; set; }
}
public class Room1
{public Grade1 Grade { get; set; }
}

我们看到这两个类的属性相互引用对方,但它们都没有定义构造函数。这里,我们以 Grade1 为例来分析一下它们的构造过程。

当我们需要一个 Grade1 对象时,容器首先调用其构造函数为我们创建一个 Grade1 对象。创建好 Grade1 对象之后,我们看到它需要注入一个 Room1 类型的属性。这样容器又会为我们创建一个 Room1 对象。随后,我们看到 Room1 也需要注入一个 Grade1 类型的属性。此时,由于之前已经创建好一个 Grade1 对象,因此容器在这里便会复用该 Grade1 对象(这一点很关键),以完成 Room1 对象的创建。随着 Room1 对象创建完成,容器跟着将该对象注入到 Grade1 的 Room 属性中,这样 Grade1 也创建完成了。因此,这里不会导致循环依赖,所以我们运行下面的代码不会导致异常:

var grade1 = container.Resolve<Grade1>();
Debug.Assert(grade1 == grade1.Room.Grade);
var room1 = container.Resolve<Room2>();
Debug.Assert(room1 == room1.Grade.Room);

接下来,我们看 Grade2/Room2。

public class Grade2
{private readonly Room2 _room;public Grade2(Room2 room){_room = room;room.Grade = this;}public Room2 Room{get { return _room; }}
}
public class Room2
{public Grade2 Grade { get; set; }
}

当我们构造 Grade2 对象时,并不会引起循环依赖。因为我们看到 Grade2 虽然在构造函数中需要 Room2,但在构造 Room2 的过程中并不需要 Grade2(因为 Room2 没有定义构造函数,而且也不需要在自身的构造过程中注入 Grade2 这个属性),所以不会有循环依赖问题。

最后我们来看 Grade3/Room3。

public class Grade3
{private readonly Room3 _room;public Grade3(Room3 room){_room = room;}public Room3 Room{get { return _room; }}
}
public class Room3
{public Grade3 Grade { get; set; }
}

我们看到 Grade3 在构造函数中需要一个 Room3 类型参数,而 Room3 类型虽然没有定义构造函数,但它在构造过程中要求注入一个 Grade3 类型的属性值。这样就引起了问题。因为当 Grade3 需要一个 Room3 对象的时候,Room3 对象尚未创建,这样容器就需要先创建一个 Room3 对象。但容器在创建 Room3 对象的过程中,又需要注入一个 Grade3 对象。然而此时最初的 Grade3 尚未创建完成(其构造函数已经被调用,但尚未完成),还无法在此处复用。因此,容器又要再创建一个新的 Grade3 对象以满足 Room3 的构造需要。随后,这个新的 Grade3 又需要一个新的 Room3,而后面这个新的 Room3 又需要一个新的 Grade3...这样永无休止地纠缠下去,这个构造过程永远不会完成。如果用比较简洁的方式来表述的话,上述创建过程的依赖路径如下:Grade3 => Room3 => Grade3 => Room3 => Grade3....

这样我们就明白了,只要我们在设计类时,注意避免产生如上所述的依赖路径,就能够有效地防止循环依赖的问题。其实,也就是遵循上面那个原则:[不要在对象构造过程中引入循环依赖]。

 

本文示例代码以及 My.Ioc 框架源码可在此处获取。

转载于:https://www.cnblogs.com/johnny-liu/p/3962814.html

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/359591.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

asp.net中两款文本编辑器NicEdit和Kindeditor

分类&#xff1a; C#/ASP.Net 2012-10-09 22:35 665人阅读 评论(0) 收藏 举报 文本编辑asp.nettextboxserveraspsafari目录(?)[] 做过Web开发的朋友相信都使用过富文本编辑器&#xff0c;比较出名的CuteEditor和CKEditor很多人应该已经使用过&#xff0c;在功能强大的同时需要…

导出oracle awr分析报告,配置oracle内存参数,察看表空间使用率

cmd 命令生成awr报告: cmd 窗口 输入 -> Sqlplus sys/orclorcl as sysdba (sys登陆oracle).导出awr命令 ?/rdbms/admin/awrrpt.sql 3..输入导出的文件格式 为 html 回车 4输入数字1 为导出今天的分析报告 &#xff0c;2 3 。。。&#xff0c;回车 5.输入开始 snap id…

android多点触控自由对图片缩放

在系统的相册中,观看相片就可以用多个手指进行缩放.要实现这个功能,只需要这几步:1.新建项目,在项目中新建一个ZoomImage.javapublic class ZoomImageView extends View {//初始化状态常量public static final int STATUS_INIT1;//图片放大状态常量public static final int STA…

jboss eclipse_调试生产服务器– Eclipse和JBoss展示

jboss eclipse您是否编写有错误的代码&#xff1f; 不&#xff0c;当然不是。 对于我们其余的人&#xff0c;他们确实会编写带有bug的代码&#xff0c;我想解决一个非常敏感的问题&#xff1a;调试在生产服务器上运行的应用程序。 因此&#xff0c;您的应用程序已准备好进行部…

Chrome 控制台不完全指南

Chrome的开发者工具已经强大到没朋友的地步了&#xff0c;特别是其功能丰富界面友好的console&#xff0c;使用得当可以有如下功效&#xff1a; 更高「逼格」更快「开发调试」更强「进阶级的Frontender」Bug无处遁形「Console大法好」console.log 大家都会用log&#xff0c;但鲜…

datanucleus_DataNucleus 3.0与Hibernate 3.5

datanucleus如官方产品站点所述&#xff0c; DataNucleus Access Platform是现有的最符合标准的开源Java持久性产品。 它完全符合JDO1 &#xff0c; JDO2 &#xff0c; JDO2.1 &#xff0c; JDO2.2 &#xff0c; JDO3 &#xff0c; JPA1和JPA2 Java标准。 它还符合OGC简单功能规…

Android学习笔记——Menu(二)

知识点&#xff1a;这次将继续上一篇文章没有讲完的Menu的学习&#xff0c;上下文菜单(Context menu)和弹出菜单(Popup menu)。 上下文菜单上下文菜单提供对UI界面上的特定项或上下文框架的操作&#xff0c;就如同Windows中右键菜单一样。 在Android中&#xff0c;有两种提供上…

eclipse卡慢解决办法

1.设置JVM运行内存 1.1编辑eclipse.ini 1.2 编辑eclipse.ini,设置jvm运行内存参数&#xff0c;最小内存&#xff1a;物理内存*0.2&#xff0c; 最大内存&#xff1a; 物理内存*0.6&#xff1b; 其中-vmargs为必须添加参数&#xff08;-vmargs的意思是设置JVM参数&#xff09;,…

QQ游戏百万人同时在线服务器架构实现

转载自&#xff1a;http://morton5555.blog.163.com/blog/static/976407162012013112545710/# QQ游戏于前几日终于突破了百万人同时在线的关口&#xff0c;向着更为远大的目标迈进&#xff0c;这让其它众多传统的棋牌休闲游戏平台黯然失色&#xff0c;相比之下&#xff0c;联众…

ruby和python_Ruby,Python和Java中的Web服务

ruby和python今天&#xff0c;我不得不准备一些示例来说明Web服务是可互操作的。 因此&#xff0c;我已经使用Metro使用Java创建了一个简单的Web服务&#xff0c;并在Tomcat上启动了它。 然后尝试使用Python和Ruby消耗它们。 这是全部完成的过程… Java中的Web服务 我从Java中…

USB描述符【整理】

USB描述符 USB描述符信息存储在USB设备中&#xff0c;在枚举过程中&#xff0c;USB主机会向USB设备发送GetDescriptor请求&#xff0c;USB设备在收到这个请求之后&#xff0c;会将USB描述符信息返回给USB主机&#xff0c;USB主机分析返回来的数据&#xff0c;判断出该设备是哪一…

什么是垃圾回收?

以下是我们的垃圾收集手册中的一个示例&#xff0c;该手册将在接下来的几周内发布。 同时&#xff0c;花点时间熟悉垃圾收集的基础知识-这将是本书的第一章。 乍一看&#xff0c;垃圾收集应该处理顾名思义的问题-查找并丢弃垃圾。 实际上&#xff0c;它所做的恰恰相反。 垃圾收…

Extjs弹窗-简单文本编辑框-Ext.Msg.show

var datavalue测试202109;//文本传入数据 Ext.Msg.show({ title:标题, msg:说明, width:600, height:500, prompt:true, multiline:200, closable:true, …

word模板插入文本域并调整表格某一个行的列宽度

一、插入文本域 操作步骤&#xff1a;插入&#xff08;菜单&#xff09;->文档部件&#xff08;菜单&#xff09;->域&#xff08;菜单&#xff09;->邮件合并->输入名称->确认 二、调整word表格某个单元格宽度 选中某行&#xff0c;按住ctrl键的同时&#xf…

java泛型视频教程_Java泛型快速教程

java泛型视频教程泛型是Java SE 5.0引入的一种Java功能&#xff0c;在其发布几年后&#xff0c;我发誓那里的每个Java程序员不仅会听说过&#xff0c;而且已经使用过。 关于Java泛型&#xff0c;有很多免费和商业资源&#xff0c;而我使用的最佳资源是&#xff1a; Java教程 …

Windows上的Oracle Java

我最近为基于Windows 7的笔记本电脑下载了JDK 9的早期访问版本 &#xff08;内部版本68 &#xff09;。 由于这是早期版本&#xff0c;因此当自动安装在笔记本电脑上安装主要Java Runtime Environment&#xff08;JRE&#xff09;引入了一些不太理想的问题时&#xff0c;我并不…

extjs弹出窗口查看文本内容-new Ext.Window

代码样例&#xff1a; function processscan(){ var text时间 用户 操作<br> 时间 用户 操作<br> 时间 用户 操作; var win new Ext.Window({ layout: fit, width: 700, height: 600, closeAction: hide, dra…

Ioc Autofac心得

对于这个容器注入&#xff0c;个人也不是很熟悉&#xff0c;很多还不懂&#xff0c;只会基本的操作&#xff0c;几天把它记录下来&#xff0c;说不定以后帮助就大了呢&#xff0c;这方面跟安卓差距还是挺大的 下面记录下应用的流程 步骤&#xff1a; 1.添加应用 2.重写工厂&…

深入学习Web Service系列----异步开发模式

概述 在本篇随笔中&#xff0c;通过一些简单的示例来说一下Web Service中的异步调用模式。调用Web Service方法有两种方式&#xff0c;同步调用和异步调用。同步调用是程序继续执行前等候调用的完成&#xff0c;而异步调用在后台继续时&#xff0c;程序也继续执行&#xff0c;不…

navicate导出导入表数据问题

1.导出导入json&#xff0c;如下图&#xff0c;右击表点击导出向导&#xff0c;选择json导出类型&#xff0c;根据提示导出即可。 导入时&#xff0c;右击接收的表&#xff0c;点击导入向导&#xff0c;根据提示即可快速导入&#xff08;注&#xff1a;不同系统之间导出导入易…