.NET高级应用---自界说Ioc容器(附带源码)

[复制链接]
发表于 2025-10-18 22:36:19 | 显示全部楼层 |阅读模式

马上注册,结交更多好友,享用更多功能,让你轻松玩转社区。

您需要 登录 才可以下载或查看,没有账号?立即注册

×
目次
1. IoC容器对象项目结构的影响
代码体现:
2. IoC容器中的对象依赖注入
代码体现:
3. IoC概念明白与自界说IoC容器
代码体现:
4. 自界说IoC容器的根本控制逻辑
5. IOC瞬态模式与单例模式逻辑整合
代码体现:
6. 无穷层级的依赖注入逻辑处置惩罚
代码体现:
7. 属性注入逻辑处置惩罚
代码体现:
8. 单接口多实现注入逻辑处置惩罚
代码体现:
9.完备代码
总结


1. IoC容器对象项目结构的影响

IoC容器的作用是将对象的创建和依赖关系的管理从代码中解耦出来,交给容器来处置惩罚。通过这种方式,项目的结构会更加清楚和模块化。
代码体现:

在你的代码中,MyIoc 类是一个自界说的IoC容器。它通过 _instenceDic 字典来管理对象的注册和实例化。这种筹划使得对象的创建和依赖关系不再硬编码在业务逻辑中,而是由容器同一管理。


  • 解耦:对象的创建和依赖关系由 MyIoc 管理,业务代码只须要通过 Resolve 方法获取实例,无需关心对象的创建过程。
  • 模块化:通过接口和抽象类界说依赖关系,具体的实现类由容器注入,加强了代码的模块化。

2. IoC容器中的对象依赖注入

依赖注入(DI)是IoC的一种实现方式。通过依赖注入,对象的依赖关系由外部容器在运行时注入,而不是在对象内部硬编码。
代码体现:

在 MyIoc 类中,依赖注入重要通过以下方式实现:


  • 构造函数注入:在 CreateInstence 方法中,通过反射获取构造函数的参数,并从容器中剖析这些参数,终极创建对象实例。
  • 属性注入:在 CreateInstence 方法中,通过反射获取对象的属性,并根据属性的标记(如 DependyAttribute)从容器中剖析并注入依赖。
比方:


  • 构造函数注入:
  1. // 构造函数注入
  2. ConstructorInfo[] cis = _instenceDic[key].ObjectType.GetConstructors();
  3. ParameterInfo[] cpis = cis[0].GetParameters();
  4. List<object> objects = new List<object>();
  5. foreach (ParameterInfo cpi in cpis)
  6. {
  7.     string paramTypeKey = cpi.ParameterType.FullName;
  8.     if (_instenceDic.ContainsKey(paramTypeKey))
  9.     {
  10.         objects.Add(_instenceDic[paramTypeKey].Instence);
  11.     }
  12. }
  13. var obj = Activator.CreateInstance(_instenceDic[key].ObjectType, objects.ToArray());
复制代码


  • 属性注入:
  1. PropertyInfo[] pis = type.GetProperties();
  2. foreach (var pi in pis)
  3. {
  4.     if (pi.IsDefined(typeof(DependyAttribute), false))
  5.     {
  6.         var attr = pi.GetCustomAttribute<DependyAttribute>();
  7.         string paramTypeKey = pi.PropertyType.FullName + (string.IsNullOrEmpty(attr.Token) ? "" : "_#%%$#_" + attr.Token);
  8.         if (_instenceDic.ContainsKey(paramTypeKey))
  9.         {
  10.             pi.SetValue(obj, _instenceDic[paramTypeKey].Instence);
  11.         }
  12.     }
  13. }
复制代码

3. IoC概念明白与自界说IoC容器

IoC的核心头脑是将对象的创建和依赖关系的管理交给外部容器,而不是在代码中硬编码。通过这种方式,代码的机动性和可维护性得到了提拔。
代码体现:

MyIoc 是一个自界说的IoC容器,它通过字典 _instenceDic 来存储注册的范例和实例。每个注册的范例都包罗一个 InstenceModel 对象,该对象记录了范例的元数据(如是否为单例)以及实例本身。


  • 注册范例:通过 Register 和 RegisterSingle 方法将范例注册到容器中。
  • 剖析实例:通过 Resolve 方法从容器中获取实例。

4. 自界说IoC容器的根本控制逻辑

MyIoc 类的根本控制逻辑如下:


  • 注册范例:




    • Register<T>():注册瞬时对象(每次哀求都创建新实例)。
    • RegisterSingle<T>():注册单例对象(整个应用步伐生命周期内只创建一个实例)。
    • Register<TFrom, TTo>():注册接口和实现类的关系。



  • 剖析实例:




    • Resolve<T>():从容器中获取实例。假如注册的范例是单例模式,则返回同一个实例;假如是瞬时模式,则每次返回新的实例。



  • 依赖注入:




    • 在创建实例时,CreateInstence 方法会递归地剖析构造函数参数和属性依赖,确保全部依赖都被精确注入。


5. IOC瞬态模式与单例模式逻辑整合

在 MyIoc 中,瞬态模式和单例模式的逻辑通过 InstenceModel 中的 IsSinglton 属性举行区分:


  • 瞬态模式:每次调用 Resolve 时,都会创建一个新的实例。
  • 单例模式:只有在第一次调用 Resolve 时创建实例,后续调用都返回同一个实例。
代码体现:

  1. if (_instenceDic[key].IsSinglton)
  2. {
  3.     if (_instenceDic[key].Instence is null)
  4.     {
  5.         lock (_instanceLock)
  6.         {
  7.             if (_instenceDic[key].Instence is null)
  8.             {
  9.                 return (T)CreateInstence(key, typeof(T));
  10.             }
  11.             return (T)_instenceDic[key].Instence;
  12.         }
  13.     }
  14.     return (T)_instenceDic[key].Instence;
  15. }
  16. else
  17. {
  18.     // 在瞬时模式下,每次都调用
  19.     return (T)CreateInstence(key, typeof(T));
  20. }
复制代码

6. 无穷层级的依赖注入逻辑处置惩罚

在 CreateInstence 方法中,通过递归调用 CreateInstence 来处置惩罚无穷层级的依赖注入。当某个对象的构造函数参数或属性依赖其他对象时,容器会递归地剖析这些依赖,直到全部依赖都被满足。
代码体现:

  1. if (_instenceDic.ContainsKey(paramTypeKey))
  2. {
  3.     if (_instenceDic[paramTypeKey].IsSinglton)
  4.     {
  5.         if (_instenceDic[paramTypeKey].Instence is null)
  6.         {
  7.             _instenceDic[paramTypeKey].Instence = CreateInstence(paramTypeKey, _instenceDic[paramTypeKey].ObjectType);
  8.         }
  9.     }
  10.     else
  11.     {
  12.         _instenceDic[paramTypeKey].Instence = CreateInstence(paramTypeKey, _instenceDic[paramTypeKey].ObjectType);
  13.     }
  14.     objects.Add(_instenceDic[paramTypeKey].Instence);
  15. }
复制代码

7. 属性注入逻辑处置惩罚

在 CreateInstence 方法中,通过反射获取对象的属性,并根据属性的标记(如 DependyAttribute)从容器中剖析并注入依赖。
代码体现:

  1. PropertyInfo[] pis = type.GetProperties();
  2. foreach (var pi in pis)
  3. {
  4.     if (pi.IsDefined(typeof(DependyAttribute), false))
  5.     {
  6.         var attr = pi.GetCustomAttribute<DependyAttribute>();
  7.         string paramTypeKey = pi.PropertyType.FullName + (string.IsNullOrEmpty(attr.Token) ? "" : "_#%%$#_" + attr.Token);
  8.         if (_instenceDic.ContainsKey(paramTypeKey))
  9.         {
  10.             pi.SetValue(obj, _instenceDic[paramTypeKey].Instence);
  11.         }
  12.     }
  13. }
复制代码

8. 单接口多实现注入逻辑处置惩罚

在 MyIoc 中,通过 Register<TFrom, TTo> 和 RegisterSingle<TFrom, TTo> 方法支持单接口多实现的注入。通过 token 参数,可以为同一个接口的差异实现指定差异的标识符,从而在剖析时区分差异的实现。
代码体现:

  1. public void Register<TFrom, TTo>(string token = "") where TTo : TFrom
  2. {
  3.     string key = typeof(TFrom).FullName + (String.IsNullOrEmpty(token) ? "" : "_#%%$#_" + token);
  4.     _instenceDic.Add(key, new InstenceModel { ObjectType = typeof(TTo), IsSinglton = false });
  5. }
复制代码
在剖析时,可以通过指定 token 来获取差异的实现:
  1. var serviceA = ioc.Resolve<IService>("A");
  2. var serviceB = ioc.Resolve<IService>("B");
复制代码

9.完备代码

  1. using System;
  2. using System.Collections.Generic;
  3. using System.Reflection;
  4. namespace MvvmLightLesson.Base
  5. {
  6.     public class MyIoc
  7.     {
  8.         private static readonly object _instanceLock = new object();
  9.         private static MyIoc instance;
  10.         private Dictionary<string, InstenceModel> _instenceDic = new Dictionary<string, InstenceModel>();
  11.         private MyIoc()
  12.         { }
  13.         public static MyIoc Default
  14.         {
  15.             get
  16.             {
  17.                 if (instance == null)
  18.                 {
  19.                     lock (_instanceLock)
  20.                     {
  21.                         if (instance == null)
  22.                         {
  23.                             instance = new MyIoc();
  24.                         }
  25.                     }
  26.                 }
  27.                 return instance;
  28.             }
  29.         }
  30.         // 瞬时状态
  31.         public void Register<T>()
  32.         {
  33.             _instenceDic.Add(
  34.                 typeof(T).FullName!,
  35.                 new InstenceModel { ObjectType = typeof(T), IsSinglton = false });
  36.         }
  37.         public void Register<TFrom, TTo>(string token = "") where TTo : TFrom
  38.         {
  39.             string key =
  40.                 typeof(TFrom).FullName +
  41.                 (String.IsNullOrEmpty(token) ? "" : "_#%%$#_" + token);
  42.             _instenceDic.Add(
  43.                 key,
  44.                 new InstenceModel { ObjectType = typeof(TTo), IsSinglton = false });
  45.         }
  46.         // 单例状态
  47.         public void RegisterSingle<T>()
  48.         {
  49.             _instenceDic.Add(
  50.                 typeof(T).FullName!,
  51.                 new InstenceModel { ObjectType = typeof(T), IsSinglton = true });
  52.         }
  53.         public void RegisterSingle<TFrom, TTo>(string token = "") where TTo : TFrom
  54.         {
  55.             string key =
  56.                 typeof(TFrom).FullName +
  57.                 (String.IsNullOrEmpty(token) ? "" : "_#%%$#_" + token);
  58.             _instenceDic.Add(
  59.                 key,
  60.                 new InstenceModel { ObjectType = typeof(TTo), IsSinglton = true });
  61.         }
  62.         public T Resolve<T>()
  63.         {
  64.             string key = typeof(T).FullName;
  65.             if (_instenceDic.ContainsKey(key))
  66.             {
  67.                 if (_instenceDic[key].IsSinglton)
  68.                 {
  69.                     if (_instenceDic[key].Instence is null)
  70.                     {
  71.                         lock (_instanceLock)
  72.                         {
  73.                             if (_instenceDic[key].Instence is null)
  74.                             {
  75.                                 // 在单例模式下,之前没有创建实例的前提下调用
  76.                                 return (T)CreateInstence(key, typeof(T));
  77.                             }
  78.                             return (T)_instenceDic[key].Instence;
  79.                         }
  80.                     }
  81.                     return (T)_instenceDic[key].Instence;
  82.                 }
  83.                 else
  84.                 {
  85.                     // 在瞬时模式下,每次都调用
  86.                     return (T)CreateInstence(key, typeof(T));
  87.                 }
  88.             }
  89.             return default(T);
  90.         }
  91.         private object CreateInstence(string key, Type type)
  92.         {
  93.             #region 检查构造函数的参数
  94.             // 如果有参数,根据类型动态创建实例
  95.             ConstructorInfo[] cis = _instenceDic[key].ObjectType.GetConstructors();
  96.             ParameterInfo[] cpis = cis[0].GetParameters();
  97.             // 参数列表
  98.             List<object> objects = new List<object>();
  99.             foreach (ParameterInfo cpi in cpis)
  100.             {
  101.                 // AAA   MySqlDA.
  102.                 string paramTypeKey = cpi.ParameterType.FullName;
  103.                 if (cpi.IsDefined(typeof(DependyAttribute), false))
  104.                 {
  105.                     var attr = cpi.GetCustomAttribute<DependyAttribute>();
  106.                     paramTypeKey += string.IsNullOrEmpty(attr.Token) ? "" : "_#%%$#_" + attr.Token;
  107.                 }
  108.                 if (_instenceDic.ContainsKey(paramTypeKey))
  109.                 {
  110.                     if (_instenceDic[paramTypeKey].IsSinglton)
  111.                     {
  112.                         if (_instenceDic[paramTypeKey].Instence is null)
  113.                         {
  114.                             //_instenceDic[paramTypeKey].Instence =
  115.                             //    Activator.CreateInstance(_instenceDic[paramTypeKey].ObjectType);
  116.                             _instenceDic[paramTypeKey].Instence =
  117.                                 CreateInstence(paramTypeKey, _instenceDic[paramTypeKey].ObjectType);
  118.                         }
  119.                     }
  120.                     else
  121.                     {
  122.                         _instenceDic[paramTypeKey].Instence =
  123.                                 CreateInstence(paramTypeKey, _instenceDic[paramTypeKey].ObjectType);
  124.                     }
  125.                     objects.Add(_instenceDic[paramTypeKey].Instence);
  126.                 }
  127.                 else
  128.                     objects.Add(null);
  129.             }
  130.             #endregion 检查构造函数的参数
  131.             // 创建对象实例,创建之前需要准备好这个对象的构造函数的参数
  132.             var obj = Activator.CreateInstance(_instenceDic[key].ObjectType, objects.ToArray());
  133.             _instenceDic[key].Instence = obj;
  134.             #region 检查属性的注入
  135.             //
  136.             // 哪些属性需要注入   可以通过特性进行区分
  137.             PropertyInfo[] pis = type.GetProperties();
  138.             //type.GetFields();// 获取所有字段
  139.             foreach (var pi in pis)
  140.             {
  141.                 // 判断属性上是否有特定标记,如果有,实例化这个属性
  142.                 if (pi.IsDefined(typeof(DependyAttribute), false))
  143.                 {
  144.                     var attr = pi.GetCustomAttribute<DependyAttribute>();
  145.                     // 属性注入的时候
  146.                     string paramTypeKey = pi.PropertyType.FullName +
  147.                         (string.IsNullOrEmpty(attr.Token) ? "" : "_#%%$#_" + attr.Token);
  148.                     if (_instenceDic.ContainsKey(paramTypeKey))
  149.                     {
  150.                         if (_instenceDic[paramTypeKey].IsSinglton)
  151.                         {
  152.                             if (_instenceDic[paramTypeKey].Instence is null)
  153.                             {
  154.                                 _instenceDic[paramTypeKey].Instence =
  155.                                     CreateInstence(paramTypeKey, _instenceDic[paramTypeKey].ObjectType);
  156.                             }
  157.                         }
  158.                         else
  159.                         {
  160.                             _instenceDic[paramTypeKey].Instence =
  161.                                     CreateInstence(paramTypeKey, _instenceDic[paramTypeKey].ObjectType);
  162.                         }
  163.                         // 如果已经创建了实例,设置给当前对象的对应属性
  164.                         // 第一个参数,指这个值要设置给哪个对象实例的这个属性
  165.                         pi.SetValue(obj, _instenceDic[paramTypeKey].Instence);
  166.                     }
  167.                 }
  168.             }
  169.             #endregion 检查属性的注入
  170.             return obj;
  171.         }
  172.         // 1、对象中的参数未注入
  173.         // 2、多个实现的使用
  174.         // 3、属性注入
  175.         // 4、瞬时注入/单例模式
  176.     }
  177.     internal class InstenceModel
  178.     {
  179.         public object Instence { get; set; }
  180.         public bool IsSinglton { get; set; }
  181.         public Type ObjectType { get; set; }
  182.     }
  183. }
复制代码

总结

通过 MyIoc 这个自界说IoC容器,我们可以看到IoC容器的核心功能:


  • 对象生命周期管理:支持瞬态模式和单例模式。
  • 依赖注入:支持构造函数注入和属性注入。
  • 机动性:支持单接口多实现的注入。
固然 MyIoc 是一个简单的实现,但它清楚地展示了IoC容器的核心头脑和实现方式。在实际项目中,可以使用更成熟的IoC容器(如Autofac、Unity等)来得到更强大的功能和更好的性能。
回复

使用道具 举报

登录后关闭弹窗

登录参与点评抽奖  加入IT实名职场社区
去登录
快速回复 返回顶部 返回列表