.NET里简易实现IoC

前言

在前面的篇幅中对依赖倒置原则和IoC框架的使用只是做了个简单的介绍,并没有很详细的去演示,可能有的朋友还是区分不了依赖倒置、依赖注入、控制反转这几个名词,或许知道的也只是知道依赖倒置是原则,依赖注入、控制反转都是实现的方式,我将在下面对这些个名词做详细的介绍,在篇幅的最后还会自己实现了IoC容器的功能。

依赖倒置原则

我们先来看一段代码,代码1-1

  1. public class Top
  2. {
  3. public void Execution()
  4. {
  5. Underly underly = new Underly();
  6. underly.WriterLine();
  7. }
  8. }
  9.  
  10. public class Underly
  11. {
  12. public void WriterLine()
  13. {
  14. Console.WriteLine("这是底层类型的输出");
  15. }
  16. }

从代码1-1中看到Top类型的Execution()方法中包含了对Underly的依赖,直接使用的New来实例化Underly类型,致使两个类型之间的耦合是属于强耦合类型,这样做会导致在需求发生变化的时候对于底层类型也就是Underly的修改会牵动到Top中的现实,而我们是不希望这种事情发生。

这个时候我们再看依赖原则的定义(度娘的):

A.高层次的模块不应该依赖于低层次的模块,他们都应该依赖于抽象。

B.抽象不应该依赖于具体,具体应该依赖于抽象。

A.高层次的模块不应该依赖于低层次的模块,他们都应该依赖于抽象

对于A,照着字面意思来说的话很简单了,已经没法办再用文字来描述了,看代码吧,

代码1-2

  1. public class Top
  2. {
  3. public void Execution()
  4. {
  5. IUnderly underly = new Underly();
  6. underly.WriterLine();
  7. }
  8. }
  9.  
  10. public interface IUnderly
  11. {
  12. void WriterLine();
  13. }
  14.  
  15. public class Underly:IUnderly
  16. {
  17. public void WriterLine()
  18. {
  19. Console.WriteLine("这是底层类型的输出");
  20. }
  21. }

在代码1-2中我们对Underly进行了抽象,并且让其依赖于抽象(也就是实现接口),而在Top类型中也依赖于抽象了。

图1

图1中所示的就是代码1-2所要表示的类型结构了,也就是依赖倒置原则中A的实现,从图1中我们可以看到依赖倒置原则里还装着开放封闭原则,这里所要说明的意思就是依赖倒置原则是开放封闭原则的基础。

从图1中的结构来看,如果是站在开放封闭原则的角度来看也是没有问题的,对扩展开放对修改关闭,在需求变动的时候只要重新实现个依赖于抽象的下层,利用多态则可实现对扩展开放。

如果是站在依赖倒置原则的角度去看,那就是符合了依赖倒置原则定义的A条。

(Ps:这里有的朋友可能会说上面的示例中Top也依赖于具体了,我只想说请注意你的人身安全,我这个人脾气不太好。

开个玩笑,对于Top也依赖于具体的事确实是有的,后面会有说明)

B.抽象不应该依赖于具体,具体应该依赖于抽象

对于依赖倒置原则定义的B来说,我分两个部分来给大家解释一下。

第一个部分就是抽象不应该依赖于具体, 我们还是通过代码来说明吧。

代码1-3

  1. public interface IUnderly
  2. {
  3. void WriterLine();
  4. IWriter CreateWriterInstance();
  5. }
  6.  
  7. public class Underly:IUnderly
  8. {
  9. public void WriterLine()
  10. {
  11. CreateWriterInstance().WriterLine();
  12. }
  13. public IWriter CreateWriterInstance()
  14. {
  15. return new Writer();
  16. }
  17. }
  18.  
  19. public interface IWriter
  20. {
  21. void WriterLine();
  22. }
  23.  
  24. public class Writer : IWriter
  25. {
  26. public void WriterLine()
  27. {
  28. Console.WriteLine("这只是一个输出");
  29. }
  30. }

首先我们新定义了一种输出方式Writer和它的抽象IWriter接口类型,我们想把它应用到Underly类型的输出中,然后我们修改了Underly的抽象类型也就是在IUnderly接口类型中新添加了一个CreateWriterInstance()方法,并且这个方法的返回类型是Writer的抽象,这样就对应了依赖倒置原则定义中B条的前半句话:抽象不应该依赖于具体。

错误的示范,代码1-4

  1. public interface IUnderly
  2. {
  3. void WriterLine();
  4. Writer CreateWriterInstance();
  5. }

这里这样的坏处很多后果也很严重,就不去细说了慢慢体会一下应该会感觉得到。

从依赖倒置原则定义中B条的前半句话中来看,我们可以在硕大的.NET Framework中看一下一些抽象的定义中是否有依赖于具体的,应该是没有至少我是没发现。

对于B条定义的后半句话,也就是第二个部分:具体应该依赖于抽象,这部分的内容就是约束我们在实际运用设计原则的时候会出现的问题,就好比上面的Top类型依然是依赖于具体了。

对于怎么解决这样的一个问题,有的朋友可能已经想到了,对的那就是依赖注入,都说依赖注入是依赖倒置原则的实现方式,这是不完全的,依赖注入解决的问题是将具体到具体的依赖转换成具体到抽象的依赖。我是这么认为的,纯属个人观点。

(ps:这是一种治标不治本的方法,DI把对象耦合的问题抛到了外部,也就是这样才导致了IoC的诞生,后面会有介绍。)

依赖注入

图2

对于上节中的示例中对象所依赖的图示。为了能像图1中所示的结构那样以及符合依赖倒置原则的定义,我们将使用依赖注入的方式,先暂时性的解决这样的问题。

依赖注入有三种方式,意思都差不多都是讲外部抽象的引用设置到内部来从而实现注入。

这里就简单示例一下,

构造函数注入

代码1-5

  1. public class Top
  2. {
  3. private IUnderly _Underly;
  4. public Top(IUnderly underly)
  5. {
  6. _Underly = underly;
  7. }
  8.  
  9. public void Execution()
  10. {
  11. _Underly.WriterLine();
  12. }
  13. }
  14. public interface IUnderly
  15. {
  16. void WriterLine();
  17. }
  18. public class Underly:IUnderly
  19. {
  20. public void WriterLine()
  21. {
  22. Console.WriteLine("这只是一个底层类型的输出");
  23. }
  24. }
  25. class Program
  26. {
  27. static void Main(string[] args)
  28. {
  29. Top top = new Top(new Underly());
  30. top.Execution();
  31.  
  32. Console.ReadLine();
  33. }
  34. }

如代码1-5所示那样,在Top类型的构造函数中定义了下层类型的抽象作为参数,以此达到依赖注入的目的。结果如图3。

图3

属性注入

代码1-6

  1. public class Top
  2. {
  3. private IUnderly _Underly;
  4. public Top() { }
  5. public Top(IUnderly underly)
  6. {
  7. _Underly = underly;
  8. }
  9.  
  10. public IUnderly Underly
  11. {
  12. get { return _Underly; }
  13. set { _Underly = value; }
  14. }
  15.  
  16. public void Execution()
  17. {
  18. _Underly.WriterLine();
  19. }
  20. }
  21. class Program
  22. {
  23. static void Main(string[] args)
  24. {
  25. Top top = new Top();
  26. top.Underly = new Underly();
  27. top.Execution();
  28.  
  29. Console.ReadLine();
  30. }
  31. }

通过在内部设置属性来获取到底层抽象的引用,结果如图3.

接口注入

代码1-7

  1. public interface IQuote
  2. {
  3. void SetQuote(IUnderly underly);
  4. }
  5.  
  6. public class Top:IQuote
  7. {
  8. private IUnderly _Underly;
  9. public Top() { }
  10. public Top(IUnderly underly)
  11. {
  12. _Underly = underly;
  13. }
  14.  
  15. public IUnderly Underly
  16. {
  17. get { return _Underly; }
  18. set { _Underly = value; }
  19. }
  20.  
  21. public void Execution()
  22. {
  23. _Underly.WriterLine();
  24. }
  25.  
  26. public void SetQuote(IUnderly underly)
  27. {
  28. _Underly = underly;
  29. }
  30. }
  31. class Program
  32. {
  33. static void Main(string[] args)
  34. {
  35. Top top = new Top();
  36. top.SetQuote(new Underly());
  37. top.Execution();
  38.  
  39. Console.ReadLine();
  40. }
  41. }

接口注入的方式原理还是一样的,让Top实现定义了设置引用方法的接口,依然是将外部的底层抽象引用设置到内部来,结果还是一样如图3.

这样虽说没什么问题了,但也只是局部的没有问题,我们看一下上面三个示例中Program类型中的测试代码,

图4

绕了一圈依赖注入是把耦合的问题抛到了外部,抛到了要使用Top类型的对象中,这个问题就很严重了,我们怎么解决呢?没关系通过IoC容器来实现。

自定义实现简易IoC

这一小节就来解决上述的问题,Ioc又叫控制反转,控制就是执行过程上的控制,反转是往哪转呢?

图5

从图5中我们可以看到,客户端调用IoC容器,并且在IoC容器中执行依赖注入操作,最后返回上层对象交给客户端,所以控制反转是由在客户端的控制权交由IoC容器,在IoC容器中进行依赖注入的操作后返回已达到控制权反转的目的,从来消弱对象间的耦合程度。

那么IoC容器要做哪些工作呢?

图6

核心功能:生成依赖注入过程中的上层对象

基础流程:

1.需要向IoC容器中注册依赖注入过程中抽象、具体。

2.在使用IoC的时候需向IoC中注册上层对象的类型。

3.解析上层对象类型,并且执行生成对象操作

4.返回上层对象实例

功能对象定义:

1.抽象、具体关系维护的对象,用以维护依赖注入过程中抽象、具体的对应关系。

2.解析对象类型的对象,根据依赖注入的几种方式分析对象类型的构造和公共属性并且生成,(公共属性是符合IoC框架中定义的标准)。

3.公共属性标准对象,用以通知IoC框架上层对象中哪些公共属性需要被注入。

4.执行过程对象,用以表示框架执行流程,框架入口点。

初步就这样定了,有可能下面定义的类型中上面没有定义到,但是不妨碍,知道基础流程就行了。那现在就开始吧。

首先我们要定义IoC框架入口点,

代码1-8

  1. namespace FrameWork.IoC.Achieve.IoCAbstractBasics
  2. {
  3. public interface IIoCKernel
  4. {
  5. IIoCKernel Bind<T>();
  6. IIoCKernel To<U>() where U : class;
  7. V GetValue<V>() where V : class;
  8. }
  9. }

对于IIoCKernel类型的定义,Bind和To两个方法用于绑定抽象、具体到关系维护的对象中,而GetValue()方法则是用以获取上层对象的实例,对于这种入口点的使用方式我是模仿的Ninject框架,会在最后的示例中演示怎么使用。(因为我只用过这一个,还是个半吊子只是简单的用过)

下面我们就来实现一下IIoCKernel,示例代码1-9.

代码1-9

  1. using FrameWork.IoC.Achieve.IoCAbstractBasics;
  2.  
  3. namespace FrameWork.IoC.Achieve.IoCBasics
  4. {
  5. public class IoCKernel : IIoCKernel
  6. {
  7. private Type _BaseType;
  8.  
  9. public IoCKernel()
  10. {
  11. IoCContext.Context.DITyoeInfoManage = new DITypeInfoManage();
  12. }
  13.  
  14. public IIoCKernel Bind<T>()
  15. {
  16. _BaseType = typeof(T);
  17. return this;
  18. }
  19.  
  20. public IIoCKernel To<U>() where U : class
  21. {
  22. Type achieveType = typeof(U);
  23. if (achieveType.BaseType == _BaseType||achieveType.GetInterface(_BaseType.Name)!=null)
  24. {
  25. IoCContext.Context.DITyoeInfoManage.AddTypeInfo(_BaseType, achieveType);
  26. }
  27. return this;
  28. }
  29.  
  30. public V GetValue<V>() where V : class
  31. {
  32. return IoCContext.Context.DITypeAnalyticalProvider.CreteDITypeAnalaytical().GetValue<V>();
  33. }
  34. }
  35. }

在代码1-9中,IoCKernel实现了IIoCKernel接口,首先在其构造函数中,我们对抽象、具体关系维护的对象进行了初始化,并且设置到了当前IoC框架的上下文中,我们这里先停一下,看一下抽象、具体关系维护对象的构造,示例代码1-10.

代码1-10

  1. namespace FrameWork.IoC.Achieve.IoCBasics
  2. {
  3. /// <summary>
  4. /// DI类型关系信息管理
  5. /// </summary>
  6. public class DITypeInfoManage
  7. {
  8. private Dictionary<Type, Type> _DITypeInfo;
  9. public DITypeInfoManage()
  10. {
  11. _DITypeInfo = new Dictionary<Type, Type>();
  12. }
  13.  
  14. /// <summary>
  15. /// 添加DI类型关系
  16. /// </summary>
  17. /// <param name="key">抽象类型</param>
  18. /// <param name="value">实现类型</param>
  19. public void AddTypeInfo(Type key, Type value)
  20. {
  21. if (key == null)
  22. {
  23. throw new ArgumentNullException("key");
  24. }
  25. if (_DITypeInfo.ContainsKey(key))
  26. {
  27. return;
  28. }
  29. if (value == null)
  30. {
  31. throw new ArgumentNullException("value");
  32. }
  33. _DITypeInfo.Add(key, value);
  34. }
  35.  
  36. /// <summary>
  37. /// 获取DI类型关系的实现类型
  38. /// </summary>
  39. /// <param name="key">抽象类型</param>
  40. /// <returns></returns>
  41. public Type GetTypeInfo(Type key)
  42. {
  43. if (key == null)
  44. {
  45. throw new ArgumentNullException("key");
  46. }
  47. if (_DITypeInfo.ContainsKey(key))
  48. {
  49. return _DITypeInfo[key];
  50. }
  51. return null;
  52. }
  53.  
  54. public bool ContainsKey(Type key)
  55. {
  56. if (key == null)
  57. {
  58. throw new ArgumentNullException("key");
  59. }
  60. return _DITypeInfo.ContainsKey(key);
  61. }
  62. }
  63. }

DITypeInfoManage类型对象表示着抽象、具体类型关系的信息维护,实则就是在内部封装了键值队,这里就不多说了,然后我们再看一下代码1-9中IoC框架入口点类型的构造函数中初始化DITypeInfoManage类型设置的上下文对象,来看示例代码1-11.

  1. using FrameWork.IoC.Achieve.IoCAbstractBasics;
  2. using FrameWork.IoC.Achieve.Providers;
  3. using FrameWork.IoC.Achieve.IoCBasics;
  4.  
  5. namespace FrameWork.IoC.Achieve
  6. {
  7. public class IoCContext
  8. {
  9. private IoCContext() { }
  10.  
  11. private static IoCContext _Context;
  12.  
  13. public static IoCContext Context
  14. {
  15. get
  16. {
  17. if (_Context == null)
  18. {
  19. _Context = new IoCContext();
  20. }
  21. return _Context;
  22. }
  23. }
  24.  
  25. private IDITypeAnalyticalProvider _DITypeAnalyticalProvider;
  26.  
  27. public IDITypeAnalyticalProvider DITypeAnalyticalProvider
  28. {
  29. get
  30. {
  31. if (_DITypeAnalyticalProvider == null)
  32. {
  33. _DITypeAnalyticalProvider = new DefualtDITypeAnalyticalProivder();
  34. }
  35. return _DITypeAnalyticalProvider;
  36. }
  37. set
  38. {
  39. _DITypeAnalyticalProvider = value;
  40. }
  41. }
  42.  
  43. private DITypeInfoManage _DITypeInfoManage;
  44.  
  45. public DITypeInfoManage DITyoeInfoManage
  46. {
  47. get
  48. {
  49. return _DITypeInfoManage;
  50. }
  51. set
  52. {
  53. _DITypeInfoManage = value;
  54. }
  55. }
  56. }
  57. }

代码1-11中的定义的IoCContext说是上下文对象,说是这么说,用以维护框架中必要的信息,实则就是一个单例模式的对象,但是意义上它还是上下文对象,在这个对象里面维护着所要依赖注入的抽象、具体类型维护的对象,这个对象我们上面代码1-10看过了,还有一个就是分析上层类型的提供程序对象,分析上层类型的提供程序对象是用以生成分析上层类型对象的,这样做便于对外扩展,我们就这样顺着往下看,看一下分析上层类型的提供程序对象,示例代码1-12。

代码1-12

  1. using FrameWork.IoC.Achieve.IoCAbstractBasics;
  2.  
  3. namespace FrameWork.IoC.Achieve.Providers
  4. {
  5. public interface IDITypeAnalyticalProvider
  6. {
  7. IDITypeAnalytical CreteDITypeAnalaytical();
  8. }
  9. }

这里的IDITypeAnalytical接口类型就是分析类型的抽象,在提供程序抽象中用以它来做返回类型,这也遵循着依赖倒置原则B条的抽象不依赖于具体。现在我们来看一下默认实现,示例代码1-13.

代码1-13

  1. using FrameWork.IoC.Achieve.IoCAbstractBasics;
  2. using FrameWork.IoC.Achieve.IoCBasics;
  3.  
  4. namespace FrameWork.IoC.Achieve.Providers
  5. {
  6. public class DefualtDITypeAnalyticalProivder:IDITypeAnalyticalProvider
  7. {
  8. public IDITypeAnalytical CreteDITypeAnalaytical()
  9. {
  10. return new DITypeAnalytical();
  11. }
  12. }
  13. }

在代码1-13中定义的就是默认的分析上层类型提供程序了,默认返回的就是我们框架中默认的分析上层类型对象,现在我们就来看一下分析上层类型对象的抽象和具体实现,示例代码1-14。

代码1-14

  1. namespace FrameWork.IoC.Achieve.IoCAbstractBasics
  2. {
  3. public interface IDITypeAnalytical
  4. {
  5. T GetValue<T>();
  6. }
  7. }

只是定义了一个泛型的GetValue()方法,泛型类型当然就是所需要执行依赖注入并且生成的上层对象类型了,这里没什么好说的,直接来看分析上层类型的具体实现吧,示例代码1-15.

代码1-15

  1. using FrameWork.IoC.Achieve.IoCAbstractBasics;
  2. using System.Reflection;
  3.  
  4. namespace FrameWork.IoC.Achieve.IoCBasics
  5. {
  6. public class DITypeAnalytical : IDITypeAnalytical
  7. {
  8.  
  9. public T GetValue<T>()
  10. {
  11. Type type = typeof(T);
  12. return (T)TypeAnalytical(type);
  13. }
  14.  
  15. private object TypeAnalytical(Type type)
  16. {
  17. ConstructorInfo[] constructorInfos = type.GetConstructors();
  18. object instance = null;
  19. #region 构造函数注入
  20. foreach (ConstructorInfo conInfo in constructorInfos)
  21. {
  22. if (conInfo.GetParameters().Length > )
  23. {
  24. ParameterInfo[] paras = conInfo.GetParameters();
  25. List<object> args = new List<object>();
  26.  
  27. foreach (ParameterInfo para in paras)
  28. {
  29. if (IoCContext.Context.DITyoeInfoManage.ContainsKey(para.ParameterType))
  30. {
  31. object par = TypeAnalytical(IoCContext.Context.DITyoeInfoManage.GetTypeInfo(para.ParameterType));
  32. args.Add(par);
  33. }
  34. }
  35. instance = CreateInstance(type, args.ToArray());
  36. break;
  37. }
  38. }
  39. #endregion
  40. if (instance == null)
  41. {
  42. instance = CreateInstance(type);
  43. }
  44. #region 属性注入
  45. if (type.GetProperties().Length > )
  46. {
  47. PropertyInfo[] proertyInfos = type.GetProperties();
  48. foreach (PropertyInfo propertyInfo in proertyInfos)
  49. {
  50. if (propertyInfo.GetCustomAttributes(typeof(DITypeAttribute), false).Length > )
  51. {
  52. if (IoCContext.Context.DITyoeInfoManage.ContainsKey(propertyInfo.PropertyType))
  53. {
  54. object propertyvalue = TypeAnalytical(IoCContext.Context.DITyoeInfoManage.GetTypeInfo(propertyInfo.PropertyType));
  55. propertyInfo.SetValue(instance, propertyvalue, null);
  56. }
  57. }
  58. }
  59. }
  60. #endregion
  61.  
  62. return instance;
  63. }
  64.  
  65. private object CreateInstance(Type type,params object[] args)
  66. {
  67. return Activator.CreateInstance(type, args);
  68. }
  69. }
  70. }

在代码1-15的定义中,主要的核心功能在TypeAnalytical()方法中,这里主要说明一下这个方法的执行过程,首先是根据方法参数传入的类型,这个类型就是要实现依赖注入的类型,为什么不说这个参数类型是上层类型?

是因为在首先执行的过程中传入的是上层类型,然后判断其类型的构造函数,读取构造函数的参数类型根据【抽象、具体类型的维护对象】来查找当前上层类型是否需要进行构造函数依赖,如果【抽象、具体类型的维护对象】中存在所需的类型,则对上层类型的构造函数参数类型进行实例创建,并且再次调用TypeAnalytical()方法,因为我们不能确定上层类型构造函数的参数类型是否需要进行依赖注入,所以这里是递归的。

在创建完上层类型构造函数的参数类型实例后,便会对上层类型进行实例创建,因为这是依赖注入中构造函数注入的一种方式。

在此完毕后判断TypeAnalytical()方法中instance实例是否为空,如果是空的则说明上层类型没有采取构造函数注入的方式,在此我们还是要创建它的实例,以便下面的进行属性注入时对实例属性的赋值。

之后我们会对上层类型的所有公共属性根据条件进行查找,查找符合我们定义标准的公共属性,也就是DITypeAttribute类型,这个类型下面会贴出示例代码,假使在找到需要依赖注入的公共属性后执行过程便和上面执行构造函数注入的方式相同。

(ps:这里功能的定义并不是很严谨,而且只针对了构造函数注入和属性注入两种方式,并没有对接口注入提供支持。)

下面我们看一下上面所说的属性注入的特性类定义(也就是框架定义的规范),示例代码1-16.

代码1-16

  1. namespace FrameWork.IoC.Achieve.IoCBasics
  2. {
  3. [AttributeUsage(AttributeTargets.Property,AllowMultiple=false,Inherited=false)]
  4. public class DITypeAttribute:Attribute
  5. {
  6. public DITypeAttribute() { }
  7. }
  8. }

就是一个简单的特性类定义,用作规范约束。

最后我们看一下测试用例:

代码1-17

  1. using FrameWork.IoC.Achieve.IoCBasics;
  2. using FrameWork.IoC.Achieve.IoCAbstractBasics;
  3.  
  4. using FrameWork.IoC.Case;
  5. using FrameWork.IoC.Case.Test.TestOne;
  6. using FrameWork.IoC.Case.Test.TestTwo;
  7.  
  8. namespace FrameWork.IoC.Case.Test
  9. {
  10. public class DITest
  11. {
  12. private IAbstractOne _AbstractOne;
  13. public DITest(IAbstractOne abstractone)
  14. {
  15. _AbstractOne = abstractone;
  16. }
  17.  
  18. private IAbstractTwo _AbstractTwo;
  19.  
  20. [DIType]
  21. public IAbstractTwo AbstractTwo
  22. {
  23. get
  24. {
  25. return _AbstractTwo;
  26. }
  27. set
  28. {
  29. _AbstractTwo = value;
  30. }
  31. }
  32.  
  33. public void Writer(string meg)
  34. {
  35. _AbstractOne.WriterLine(meg);
  36. _AbstractTwo.WriterLine(meg);
  37. }
  38. }
  39. }

代码1-17定义中对DITest分别进行了构造函数、属性注入,注入类型分别对应着IAbstractOne、IAbstractTwo。我们先来看一下IAbstractOne抽象、具体的定义,示例代码1-18

代码1-18

  1. namespace FrameWork.IoC.Case.Test.TestOne
  2. {
  3. public interface IAbstractOne
  4. {
  5. void WriterLine(string meg);
  6. }
  7.  
  8. public class AchieveOne:IAbstractOne
  9. {
  10. private IAbstractOne_One _AbstractOne_One;
  11. public AchieveOne(IAbstractOne_One abstractone)
  12. {
  13. _AbstractOne_One = abstractone;
  14. }
  15.  
  16. private IAbstractOne_Two _AbstractOne_Two;
  17.  
  18. [DIType]
  19. public IAbstractOne_Two AbstractOne_Two
  20. {
  21. get
  22. {
  23. return _AbstractOne_Two;
  24. }
  25. set
  26. {
  27. _AbstractOne_Two = value;
  28. }
  29. }
  30.  
  31. public void WriterLine(string meg)
  32. {
  33. _AbstractOne_One.WirterLine(meg);
  34. _AbstractOne_Two.WriterLine(meg);
  35. Console.WriteLine(meg + "-This is TestOne");
  36. }
  37. }
  38.  
  39. }

代码1-18中定义了IAbstractOne抽象、AchieveOne具体实现,并且在AchieveOne具体实现中还对IAbstractOne_One、IAbstractOne_Two分别进行了构造函数、属性注入。从最上层来看就是嵌套的注入,这样更能体现出IoC框架的重要性。

我们看一下IAbstractOne_One、IAbstractOne_Two类型的抽象、具体定义,示例代码1-19.

代码1-19

  1. namespace FrameWork.IoC.Case.Test.TestOne
  2. {
  3. public interface IAbstractOne_One
  4. {
  5. void WirterLine(string meg);
  6. }
  7.  
  8. public class AbstractOne_One:IAbstractOne_One
  9. {
  10. public void WirterLine(string meg)
  11. {
  12. Console.WriteLine(meg + "-This is TestOne_One");
  13. }
  14. }
  15.  
  16. public interface IAbstractOne_Two
  17. {
  18. void WriterLine(string meg);
  19. }
  20.  
  21. public class AbstractOne_Two:IAbstractOne_Two
  22. {
  23. public void WriterLine(string meg)
  24. {
  25. Console.WriteLine(meg + "-This is TestOne_Two");
  26. }
  27. }
  28.  
  29. }

最后我们再看一下IAbstractTwo抽象和具体实现的定义,示例代码1-20.

代码1-20

  1. namespace FrameWork.IoC.Case.Test.TestTwo
  2. {
  3. public interface IAbstractTwo
  4. {
  5. void WriterLine(string meg);
  6. }
  7.  
  8. public class AchieveTwo:IAbstractTwo
  9. {
  10. public void WriterLine(string meg)
  11. {
  12. Console.WriteLine(meg + "-This is TestTwo");
  13. }
  14. }
  15.  
  16. }

真的是最后我们看一下客户端的调用代码,示例代码1-21,

代码1-21

  1. using FrameWork.IoC.Achieve.IoCBasics;
  2. using FrameWork.IoC.Achieve.IoCAbstractBasics;
  3.  
  4. using FrameWork.IoC.Case;
  5. using FrameWork.IoC.Case.Test;
  6. using FrameWork.IoC.Case.Test.TestOne;
  7. using FrameWork.IoC.Case.Test.TestTwo;
  8.  
  9. namespace FrameWork.IoC.Case
  10. {
  11. class Program
  12. {
  13. static void Main(string[] args)
  14. {
  15. #region IoCTest
  16. IIoCKernel iocKernel = new IoCKernel();
  17. iocKernel.Bind<IAbstractOne>().To<AchieveOne>();
  18. iocKernel.Bind<IAbstractTwo>().To<AchieveTwo>();
  19. iocKernel.Bind<IAbstractOne_One>().To<AbstractOne_One>();
  20. iocKernel.Bind<IAbstractOne_Two>().To<AbstractOne_Two>();
  21. DITest diType = iocKernel.GetValue<DITest>();
  22. diType.Writer("IoCFrameWorkTest");
  23. #endregion
  24. Console.ReadLine();
  25. }
  26. }
  27. }

最后看一下结果,如图7

图7

到这里本篇的内容就结束了,自定义IoC只是一个参考,并没有对IoC框架进行深入的实现,只是以此做一个引导,建议大家还是选择一款合适的IoC框架当作学习的对象,当然感兴趣的朋友还是可以自己写的。

搬砖不易,且搬且用心,感谢各位工友的支持,谢谢大家。

作者:金源

出处:http://www.cnblogs.com/jin-yuan/

.NET实现IoC的更多相关文章

  1. 学习AOP之透过Spring的Ioc理解Advisor

    花了几天时间来学习Spring,突然明白一个问题,就是看书不能让人理解Spring,一方面要结合使用场景,另一方面要阅读源代码,这种方式理解起来事半功倍.那看书有什么用呢?主要还是扩展视野,毕竟书是别 ...

  2. 【调侃】IOC前世今生

    前些天,参与了公司内部小组的一次技术交流,主要是针对<IOC与AOP>,本着学而时习之的态度及积极分享的精神,我就结合一个小故事来初浅地剖析一下我眼中的“IOC前世今生”,以方便初学者能更 ...

  3. 深入理解DIP、IoC、DI以及IoC容器

    摘要 面向对象设计(OOD)有助于我们开发出高性能.易扩展以及易复用的程序.其中,OOD有一个重要的思想那就是依赖倒置原则(DIP),并由此引申出IoC.DI以及Ioc容器等概念.通过本文我们将一起学 ...

  4. 自己实现简单Spring Ioc

    IoC则是一种 软件设计模式,简单来说Spring通过工厂+反射来实现IoC. 原理简单说明: 其实就是通过解析xml文件,通过反射创建出我们所需要的bean,再将这些bean挨个放到集合中,然后对外 ...

  5. 使用Microsoft的IoC框架:Unity来对.NET应用进行解耦

    1.IoC/DI简介 IoC 即 Inversion of Control,DI 即 Dependency Injection,前一个中文含义为控制反转,后一个译为依赖注入,可以理解成一种编程模式,详 ...

  6. DIP原则、IoC以及DI

    一.DIP原则 高层模块不应该依赖于底层模块,二者都应该依赖于抽象. 抽象不应该依赖于细节,细节应该依赖于抽象. 该原则理解起来稍微有点抽象,我们可以将该原则通俗的理解为:"依赖于抽象&qu ...

  7. 【初探Spring】------Spring IOC(三):初始化过程---Resource定位

    我们知道Spring的IoC起到了一个容器的作用,其中装得都是各种各样的Bean.同时在我们刚刚开始学习Spring的时候都是通过xml文件来定义Bean,Spring会某种方式加载这些xml文件,然 ...

  8. 【初探Spring】------Spring IOC(二):初始化过程---简介

    首先我们先来看看如下一段代码 ClassPathResource resource = new ClassPathResource("bean.xml"); DefaultList ...

  9. 【初探Spring】------Spring IOC(一)

    IOC:Inversion of Control(控制反转).IOC它所体现的并不是一种技术,而是一种思想,一种将设计好的对象交给容器来管理的思想.IOC的核心思想就体现在控制.反转这两个词上面,要理 ...

  10. .NET里简易实现IoC

    .NET里简易实现IoC 前言 在前面的篇幅中对依赖倒置原则和IoC框架的使用只是做了个简单的介绍,并没有很详细的去演示,可能有的朋友还是区分不了依赖倒置.依赖注入.控制反转这几个名词,或许知道的也只 ...

随机推荐

  1. javaweb(2)之Servlet入门

    Hello Servlet 方式一 1.新建 web 工程,编写一个类,实现 javax.servlet.Servlet 接口: package com.zze.servlet; import jav ...

  2. 建立请求号 request

    1:获取TR号(一般由团队的负责人创建,发出) 2:进入 i7p系统 3:点击process 4:输入tr号 5:选中 正确的请求号,右键> process item> add task ...

  3. Linux显示su:认证失败

    1. sudo passwd 2.输入安装密码 3.输入新的Unix的root密码 4.重复密码 5.su 6.输入上面的新密码

  4. Vue使用Typescript开发编译时提示“ERROR in ./src/main.ts Module build failed: TypeError: Cannot read property 'afterCompile' of undefined”的解决方法

    使用Typescript开发Vue,一切准备就绪.但npm start 时,提示“ ERROR in ./src/main.tsModule build failed: TypeError: Cann ...

  5. from dns.resolver import Resolver ImportError: No module named dns.resolver

    from dns.resolver import Resolver ImportError: No module named dns.resolver python2运行BBScan时提示: from ...

  6. angularjs 的ng-disabled属性操作

    ng-readonly:不可用,但是可以提交数据 ng-disabled: 属性是控制标签是否可用(不可用且无法传值) 表达式控制: <input class="col-md-2 fo ...

  7. java之导入excel

    接口: /** * * Description: 导入excel表 * @param map * @param request * @param session * @return * @author ...

  8. nodejs笔记之文件操作

    文件操作包含: 读取文件 写入文件 删除文件 创建目录 删除目录 读取文件: // 异步操作 var fs = require("fs"); fs.readFile(". ...

  9. 判断(if)语句

    目标 开发中的应用场景 if语句体验 if语句进阶 综合应用 一 开发中的应用场景 转换成代码 判断的定义 如果 条件满足,才能做某件事 如果 条件不满足,就做另外一件事,或者什么也不做 判断语句 又 ...

  10. 常用python的标准库

    1.itsdangerous # 加密签名的数据 2.re # 正则表达式 3.time # 时间模块 4.keyword # 查看关键字5.random # 随机6.uuid