IoC原理-使用反射/Emit来实现一个最简单的IoC容器

参考文章https://www.cnblogs.com/kklldog/p/3395641.htmlhttps://www.cnblogs.com/MedlarCanFly/p/11430057.html

  1  #region
  2 
  3     #region 1.定义IIoCConfig接口
  4     public interface IIoCConfig
  5     {
  6         void AddConfig<TInterface, TType>();
  7 
  8         Dictionary<Type, Type> ConfigDictionary { get; }
  9     }
 10     #endregion
 11     //试过两者在emit和Activator.CreateInstance两者获得实现。Activator.CreateInstance效率更高
 12     #region 2.定义IoCConfig实现
 13 
 14     //使用一个字典来保存Interface跟Class的对应关系。这里是仿造Ninject的配置方式,使用代码来配置。
 15     //这种配置方式有个好处就是不会写错,因为有IDE来给你检查拼写错误。不要小看这个好处,
 16     //当你有上百个注入对象的时候,使用Unity的XML来配置对应关系的时候很容易就会发生拼写错误。这种错误往往还很难发现。
 17     //当然这里要实现一个按照XML配置文件来设置对应关系的类也很容易,这里就不实现了。
 18     public class IoCConfig : IIoCConfig
 19     {
 20         public Dictionary<Type, Type> ConfigDictionary { get; } = new Dictionary<Type, Type>();
 21 
 22         /// <summary>
 23         /// 添加配置
 24         /// </summary>
 25         /// <typeparam name="TInterface">接口</typeparam>
 26         /// <typeparam name="TType">实现接口的类型</typeparam>
 27         public void AddConfig<TInterface, TType>()
 28         {
 29             //判断TType是否实现TInterface
 30             if (typeof(TInterface).IsAssignableFrom(typeof(TType)))
 31             {
 32                 ConfigDictionary.Add(typeof(TInterface), typeof(TType));
 33             }
 34             else
 35             {
 36                 throw new Exception("类型未实现接口");
 37             }
 38         }
 39     }
 40     #endregion
 41 
 42     #region 3.定义IIoCContainer容器接口
 43     /// <summary>
 44     /// ioc容器接口
 45     /// </summary>
 46     public interface IIoCContainer
 47     {
 48         /// <summary>
 49         /// 根据接口返回对应的实例
 50         /// </summary>
 51         /// <typeparam name="TInterface"></typeparam>
 52         /// <returns></returns>
 53         TInterface Get<TInterface>();
 54     }
 55     #endregion
 56 
 57     #region 4.使用反射实现IoC容器
 58     /// <summary>
 59     /// 使用反射实现IoC容器
 60     /// </summary>
 61     public class ReflectionContainer : IIoCContainer
 62     {
 63         /// <summary>
 64         /// 配置实例
 65         /// </summary>
 66         private IIoCConfig _config;
 67 
 68         /// <summary>
 69         /// 构造函数
 70         /// </summary>
 71         /// <param name="config">ioc配置</param>
 72         public ReflectionContainer(IIoCConfig config)
 73         {
 74             _config = config;
 75         }
 76 
 77         /// <summary>
 78         /// 根据接口获取实例对象
 79         /// </summary>
 80         /// <typeparam name="TInterface">接口</typeparam>
 81         /// <returns></returns>
 82         public TInterface Get<TInterface>()
 83         {
 84             Type type;
 85             var can = _config.ConfigDictionary.TryGetValue(typeof(TInterface), out type);
 86             if (can)
 87             {
 88                 //反射实例化对象
 89                 return (TInterface)Activator.CreateInstance(type);
 90             }
 91             else
 92             {
 93                 throw new Exception("未找到对应的类型");
 94             }
 95         }
 96     }
 97     #endregion
 98     /// <summary>
 99     /// 使用Emit实现IoC容器
100     /// </summary>
101     public class EmitContainer : IIoCContainer
102     {
103         /// <summary>
104         /// 配置实例
105         /// </summary>
106         private IIoCConfig _config;
107 
108         public EmitContainer(IIoCConfig config)
109         {
110             _config = config;
111         }
112 
113         /// <summary>
114         /// 获取实例
115         /// </summary>
116         /// <typeparam name="TInterface">接口</typeparam>
117         /// <returns></returns>
118         public TInterface Get<TInterface>()
119         {
120             Type type;
121             var can = _config.ConfigDictionary.TryGetValue(typeof(TInterface), out type);
122             if (can)
123             {
124                 BindingFlags defaultFlags = BindingFlags.Public | BindingFlags.Instance;
125                 var constructors = type.GetConstructors(defaultFlags);//获取默认构造函数
126                 var t = (TInterface)this.CreateInstanceByEmit(constructors[0]);
127                 return t;
128             }
129             else
130             {
131                 throw new Exception("未找到对应的类型");
132             }
133         }
134 
135         /// <summary>
136         /// 实例化对象 用EMIT
137         /// </summary>
138         /// <typeparam name="T"></typeparam>
139         /// <param name="constructor">构造函数信息</param>
140         /// <returns></returns>
141         private Object CreateInstanceByEmit(ConstructorInfo constructor)
142         {
143             //动态方法
144             var dynamicMethod = new DynamicMethod(Guid.NewGuid().ToString("N"), typeof(Object), new[] { typeof(object[]) }, true);
145             //方法IL
146             ILGenerator il = dynamicMethod.GetILGenerator();
147             //实例化命令
148             il.Emit(OpCodes.Newobj, constructor);
149             //如果是值类型装箱
150             if (constructor.ReflectedType.IsValueType)
151                 il.Emit(OpCodes.Box, constructor.ReflectedType);
152             //返回
153             il.Emit(OpCodes.Ret);
154             //用FUNC去关联方法
155             var func = (Func<Object>)dynamicMethod.CreateDelegate(typeof(Func<Object>));
156             //执行方法
157             return func.Invoke();
158         }
159     }
160     //Emit的实现是抄自Ninject的实现方式。这里其实就是在手动书写IL。一个简单的书写IL的办法就是先用C#写好代码,然后用Reflector等反编译工具查看生成的IL,然后改成Emit代码。
161 
162     /// <summary>
163     /// 实现IoCContainerManager
164     /// </summary>
165     public class IoCContainerManager
166     {
167         /// <summary>
168         /// 容器
169         /// </summary>
170         private static IIoCContainer _container;
171 
172         /// <summary>
173         /// 获取IOC容器
174         /// </summary>
175         /// <param name="config">ioc配置</param>
176         /// <returns></returns>
177         public static IIoCContainer GetIoCContainer(IIoCConfig config)
178         {
179 
180             if (_container == null)
181             {
182                 //反射方式
183                 _container = new ReflectionContainer(config);
184                 //EMIT方式
185                 // _container=new EmitContainer(config);
186             }
187             return _container;
188 
189         }
190     }
191 
192     #endregion
View Code
原文地址:https://www.cnblogs.com/hudean/p/11771510.html