.NET里简易实现IoC

简介:

.NET里简易实现IoC

前言

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

 

依赖倒置原则

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

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

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

 

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

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

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

 

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

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

代码1-2

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

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

图1

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

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

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

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

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

 

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

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

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

代码1-3

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

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

错误的示范,代码1-4

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

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

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

 

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

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

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

 

依赖注入

图2

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

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

这里就简单示例一下,

构造函数注入

代码1-5

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

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

图3

 

属性注入

代码1-6

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

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

 

接口注入

代码1-7

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

接口注入的方式原理还是一样的,让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
2
3
4
5
6
7
8
9
namespace  FrameWork.IoC.Achieve.IoCAbstractBasics
{
     public  interface  IIoCKernel
     {
         IIoCKernel Bind<T>();
         IIoCKernel To<U>()  where  U :  class ;
         V GetValue<V>()  where  V :  class ;
     }
}

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

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

代码1-9

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

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

代码1-10

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

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

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

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

代码1-12

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

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

代码1-13

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

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

代码1-14

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

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

代码1-15

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

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

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

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

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

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

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

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

代码1-16

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

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

 

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

代码1-17

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

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

代码1-18

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

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

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

代码1-19

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

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

代码1-20

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

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

代码1-21

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

最后看一下结果,如图7

图7

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

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









     本文转自jinyuan0829 51CTO博客,原文链接:http://blog.51cto.com/jinyuan/1434222,如需转载请自行联系原作者






相关文章
|
容器
.net core Autofac IOC 容器的简单使用
## 书接上回,介绍了[.net core 读取配置文件的几种方式](https://developer.aliyun.com/article/1363340?spm=a2c6h.13148508.setting.14.21764f0ehMR1KI ".net core 读取配置文件的几种方式"),本文学习Autofac的同时再次增加一种读取配置文件的方法。 ## 本文介绍Auofac,一个优秀的.NET IOC框架 ## 源码地址:https://github.com/autofac/Autofac # 1、打开NuGet包管理器安装Autofac.Extensions.Dependenc
154 0
|
前端开发 C# 图形学
【.NET6+WPF】WPF使用prism框架+Unity IOC容器实现MVVM双向绑定和依赖注入
前言:在C/S架构上,WPF无疑已经是“桌面一霸”了。在.NET生态环境中,很多小伙伴还在使用Winform开发C/S架构的桌面应用。但是WPF也有很多年的历史了,并且基于MVVM的开发模式,受到了很多开发者的喜爱。
812 0
【.NET6+WPF】WPF使用prism框架+Unity IOC容器实现MVVM双向绑定和依赖注入
|
Java 中间件 图形学
.NET下各种IoC框架对Xamarin的支持程序
.NET有的IoC框架比较有名的有Autofac,CastleWindsor,Spring.NET,NInject,Unity和StructureMap,Xamarin.Forms本身也提供一个简单的DI实现叫DependService类。本文介绍一下这几种IoC容器对Xamarin的支持情况。
877 0
|
图形学 容器
一起谈.NET技术,IoC+AOP的简单实现
  对EnterLib有所了解的人应该知道,其中有一个名叫Policy Injection的AOP框架;而整个EnterLib完全建立在另一个叫作Unity的底层框架之上,我们可以将Unity看成是一个IoC的框架。
1045 0
|
数据库 容器
.NET Core2.1下采用EFCore比较原生IOC、AspectCore、AutoFac之间的性能
一、前言  ASP.NET Core本身已经集成了一个轻量级的IOC容器,开发者只需要定义好接口后,在Startup.cs的ConfigureServices方法里使用对应生命周期的绑定方法即可,常见方法如下 services.
2790 0
|
XML JavaScript API
从壹开始前后端分离【 .NET Core2.0 +Vue2.0 】框架之九 || 依赖注入IoC学习 + AOP界面编程初探
更新 1、感谢@dongfo博友的提醒,目前是vue-cli脚手架是3.0.1,vue的版本还是2.5.17,下文已改,感谢纠错! 2、代码已经同步到码云https://gitee.com/laozhangIsPhi/Blog.
2030 0
|
容器
.net core2.1 三层中使用Autofac代替原来Ioc
原文:.net core2.1 三层中使用Autofac代替原来Ioc   首先,现有的三层项目的结构 其中  Repository public interface IPersonRepository { string Eat(); } ...
1661 0
|
Web App开发 容器
.Net IOC框架入门之二 CastleWindsor
一、简介 Castle是.net平台上的一个开源项目,为企业级开发和WEB应用程序开发提供完整的服务,用于提供IOC的解决方案.IOC被称为控制反转或者依赖注入(Dependency Injection)。
1660 0

热门文章

最新文章