让我手把手教你写一个强大、方便使用的 IOC 容器
source link: https://www.cnblogs.com/PatrickLiu/p/14998785.html
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.
posts - 173, comments - 414, views -
105万
一、介绍
1、介绍
最近无聊,也没什么事做,没事做总是要给自己找点事情做吧,毕竟人的生活在与折腾。于是,决定自己手动写一个 IOC 的框架。我们知道在 NetCore 的版本里面已经内置了 IOC 容器,它就是 ServiceCollection,一般情况下,该容器还是够用的,但是有时候还会有力不从心的时候,比如:我想要实现属性注入或者方法注入,NetCore 内置的框架就不可以实现。还有情况是,我们要实现对同一接口的多实例注入也没办法实现。当然还有其他情况,比如,没有实现 AOP 的功能。最近正好无事可做,正好利用这段时间,自己亲手写一套 IOC 的框架,当然了,要重写,肯定要比 NetCore 内置的要强,否则,也就没有写的必要了,说干就干。
2、开发环境
1)、操作系统:Windows 10 专业版本。
2)、开发工具:Visual Studio 2019 社区版,16.8.3
3)、开发语言:C#
4)、框架版本:Net 5.0,该版本是跨平台版本,但是不是长期版本,6.0 是 LTS 版本。
3、实现目标
1)、该框架可以实现构造函数注入。
2)、该框架可以实现方法注入。
3)、该框架可以实现属性注入。
4)、该框架可以实现无限层级激活。
5)、该框架可以实现注册服务的多种声明周期,分别是:Transient,Singleton,Scoped,PerThread
6)、该框架可以实现针对同一接口的多实例注册。
7)、当一个类型在实例化的时候可以增加参数。
以上就是该框架的目标,应该还不错吧。毕竟我们自己手写了框架代码,让我们会更加了解 IOC 的定义和实现。
二、手写框架
1、我先把该框架的主要类型的代码贴出来,这个类型是核心类型,实现了我们上面定义的目标。
首先、我们为 IOC 容器定义接口,面向接口编程嘛,可不要忘记了,所以,我们先顶一个接口,类型名称:ICustomContainer。
1 /// <summary> 2 /// 我们定义的 IOC 容器抽象基类型,它定义了 IOC 容器的核心功能。 3 /// </summary> 4 public interface ICustomContainer 5 { 6 /// <summary> 7 /// 提供服务的名称和参数构建实例以 TFrom 类型注册 TTo 实例。 8 /// </summary> 9 /// <typeparam name="TFrom">TTo 的基类类型。</typeparam> 10 /// <typeparam name="TTo">TFrom 的子类类型。</typeparam> 11 /// <param name="serviceName">要注册服务的名称。</param> 12 /// <param name="lifetime">要注册的服务的生命周期。</param> 13 /// <param name="parameterValues">要注册的服务在构建实例时需要的非注入参数。</param> 14 void Register<TFrom, TTo>(string serviceName, ServiceLifetime lifetime, params object[] parameterValues) where TTo : TFrom; 15 16 /// <summary> 17 /// 以指定名称解析该基类型的实例。 18 /// </summary> 19 /// <typeparam name="TFrom">要解析实例的基类型。</typeparam> 20 /// <param name="serviceName">要解析实例的名称。</param> 21 /// <returns></returns> 22 TFrom Resolve<TFrom>(string serviceName); 23 }
再者,就是该接口的实现类型,该类型也是该容器的核心代码。代码不是很难,大家直接看吧。
类型名称:PatrickContainer
1 using System; 2 using System.Collections.Concurrent; 3 using System.Collections.Generic; 4 using System.Linq; 5 using System.Reflection; 6 using System.Threading; 7 8 namespace PatrickLiu.NetCore50.IOCFramework.Container 9 { 10 /// <summary> 11 /// 自定义的IOC容器实现。 12 /// </summary> 13 public sealed class PatrickContainer: ICustomContainer 14 { 15 private readonly IDictionary<string, ServiceMetadata> _Container; 16 private readonly IDictionary<string, object[]> _Parameters; 17 private readonly IDictionary<string, object> _ScopedContainer; 18 19 20 /// <summary> 21 /// 初始化类型的新实例,实例化容器。 22 /// </summary> 23 public PatrickContainer() 24 { 25 _Container = new ConcurrentDictionary<string, ServiceMetadata>(); 26 _Parameters = new ConcurrentDictionary<string, object[]>(); 27 _ScopedContainer = new Dictionary<string, object>(); 28 } 29 30 /// <summary> 31 /// 可以创建子作用域。 32 /// </summary> 33 /// <returns></returns> 34 public PatrickContainer CreateScoped() 35 { 36 return new PatrickContainer(_Container, _Parameters, new Dictionary<string, object>()); 37 } 38 39 /// <summary> 40 /// 通过是有构造函数初始化容器。 41 /// </summary> 42 /// <param name="container"></param> 43 /// <param name="parameters"></param> 44 /// <param name="scopedContainer"></param> 45 private PatrickContainer(IDictionary<string, ServiceMetadata> container, IDictionary<string, object[]> parameters, IDictionary<string, object> scopedContainer) 46 { 47 this._Container = container; 48 this._Parameters = parameters; 49 this._ScopedContainer = scopedContainer; 50 } 51 52 /// <summary> 53 /// 以 TFrom 类型注册 TTo 实例。 54 /// </summary> 55 /// <typeparam name="TFrom">TTo 的基类类型</typeparam> 56 /// <typeparam name="TTo">TFrom 的子类类型。</typeparam> 57 public void Register<TFrom, TTo>() where TTo : TFrom 58 { 59 Register<TFrom, TTo>(null, ServiceLifetime.Transient, null); 60 } 61 62 /// <summary> 63 /// 以 TFrom 类型注册 TTo 实例。 64 /// </summary> 65 /// <typeparam name="TFrom">TTo 的基类类型</typeparam> 66 /// <typeparam name="TTo">TFrom 的子类类型。</typeparam> 67 /// <param name="lifetime">要注册的服务的生命周期。</param> 68 public void Register<TFrom, TTo>(ServiceLifetime lifetime) where TTo : TFrom 69 { 70 Register<TFrom, TTo>(null, lifetime, null); 71 } 72 73 /// <summary> 74 /// 提供服务构建实例所需参数来以 TFrom 类型注册 TTo 实例。 75 /// </summary> 76 /// <typeparam name="TFrom">TTo 的基类类型</typeparam> 77 /// <typeparam name="TTo">TFrom 的子类类型。</typeparam> 78 /// <param name="parameterValues">要注册的服务在构建实例时需要的非注入参数。</param> 79 public void Register<TFrom, TTo>(params object[] parameterValues) where TTo : TFrom 80 { 81 Register<TFrom, TTo>(null, ServiceLifetime.Transient, parameterValues); 82 } 83 84 /// <summary> 85 /// 提供服务的名称构建实例来以 TFrom 类型注册 TTo 实例。 86 /// </summary> 87 /// <typeparam name="TFrom">TTo 的基类类型</typeparam> 88 /// <typeparam name="TTo">TFrom 的子类类型。</typeparam> 89 /// <param name="serviceName">要注册服务的名称。</param> 90 public void Register<TFrom, TTo>(string serviceName) where TTo : TFrom 91 { 92 Register<TFrom, TTo>(serviceName, ServiceLifetime.Transient, null); 93 } 94 95 /// <summary> 96 /// 提供服务的名称构建实例来以 TFrom 类型注册 TTo 实例。 97 /// </summary> 98 /// <typeparam name="TFrom">TTo 的基类类型</typeparam> 99 /// <typeparam name="TTo">TFrom 的子类类型。</typeparam> 100 /// <param name="serviceName">要注册服务的名称。</param> 101 /// <param name="lifetime">要注册的服务的生命周期。</param> 102 public void Register<TFrom, TTo>(string serviceName, ServiceLifetime lifetime) where TTo : TFrom 103 { 104 Register<TFrom, TTo>(serviceName, lifetime, null); 105 } 106 107 /// <summary> 108 /// 提供服务的名称和参数构建实例以 TFrom 类型注册 TTo 实例。 109 /// </summary> 110 /// <typeparam name="TFrom">TTo 的基类类型</typeparam> 111 /// <typeparam name="TTo">TFrom 的子类类型。</typeparam> 112 /// <param name="serviceName">要注册服务的名称。</param> 113 /// <param name="lifetime">要注册的服务的生命周期。</param> 114 /// <param name="parameterValues">要注册的服务在构建实例时需要的非注入参数。</param> 115 public void Register<TFrom, TTo>(string serviceName, ServiceLifetime lifetime, params object[] parameterValues) where TTo : TFrom 116 { 117 string key; 118 if (string.IsNullOrEmpty(serviceName) || string.IsNullOrWhiteSpace(serviceName)) 119 { 120 key = typeof(TFrom).FullName; 121 if (!_Container.ContainsKey(key)) 122 { 123 _Container.Add(key, new ServiceMetadata() { ServiceType = typeof(TTo), Lifetime = lifetime }); 124 } 125 } 126 else 127 { 128 key = string.Format("{0}_{1}", typeof(TFrom).FullName, serviceName); 129 if (!_Container.ContainsKey(key)) 130 { 131 _Container.Add(key, new ServiceMetadata() { ServiceType = typeof(TTo), Lifetime = lifetime }); 132 } 133 } 134 if (parameterValues != null && parameterValues.Length > 0) 135 { 136 _Parameters.Add(key, parameterValues); 137 } 138 } 139 140 /// <summary> 141 /// 以指定类型解析该类型的实例。 142 /// </summary> 143 /// <typeparam name="TFrom">要解析实例的基类型。</typeparam> 144 /// <returns></returns> 145 public TFrom Resolve<TFrom>() 146 { 147 return Resolve<TFrom>(null); 148 } 149 150 /// <summary> 151 /// 以指定名称解析该基类型的实例。 152 /// </summary> 153 /// <typeparam name="TFrom">要解析实例的基类型。</typeparam> 154 /// <param name="serviceName">要解析实例的名称。</param> 155 /// <returns></returns> 156 public TFrom Resolve<TFrom>(string serviceName) 157 { 158 return (TFrom)Create(typeof(TFrom), serviceName); 159 } 160 161 162 /// <summary> 163 /// 通过递归实现解析实例对象。 164 /// </summary> 165 /// <param name="baseType">服务的基类型。</param> 166 /// <param name="serviceName">服务实例的名称。</param> 167 /// <returns></returns> 168 private object Create(Type baseType, string serviceName = null) 169 { 170 #region 处理关键字 171 172 string keyword; 173 174 if (string.IsNullOrEmpty(serviceName) || string.IsNullOrWhiteSpace(serviceName)) 175 { 176 keyword = string.Format("{0}", baseType.FullName); 177 } 178 else 179 { 180 keyword = string.Format("{0}_{1}", baseType.FullName, serviceName); 181 } 182 183 #endregion 184 185 Type targetType = null; ServiceLifetime lifetime = ServiceLifetime.Transient; 186 if (_Container.ContainsKey(keyword)) 187 { 188 targetType = _Container[keyword].ServiceType; 189 lifetime = _Container[keyword].Lifetime; 190 } 191 else if (keyword.IndexOf('_') != -1) 192 { 193 if (_Container.ContainsKey(keyword.Split('_')[0])) 194 { 195 keyword = keyword.Split('_')[0]; 196 targetType = _Container[keyword].ServiceType; 197 lifetime = _Container[keyword].Lifetime; 198 } 199 } 200 else 201 { 202 throw new Exception("类型还未注册!"); 203 } 204 205 #region 生命周期 206 207 switch (lifetime) 208 { 209 case ServiceLifetime.Transient: 210 break; 211 case ServiceLifetime.Singleton: 212 if (_Container[keyword].SingletonInstance != null) 213 { 214 return _Container[keyword].SingletonInstance; 215 } 216 break; 217 case ServiceLifetime.Scoped: 218 if (_ScopedContainer.ContainsKey(keyword)) 219 { 220 return _ScopedContainer[keyword]; 221 } 222 break; 223 case ServiceLifetime.PerThread: 224 var objInstance = CallContext.GetData($"{keyword}{Thread.CurrentThread.ManagedThreadId}"); 225 if (objInstance != null) 226 { 227 return objInstance; 228 } 229 break; 230 default: 231 break; 232 } 233 234 #endregion 235 236 #region 选择构造函数 237 238 ConstructorInfo ctor = null; 239 240 //1、通过特性约束 241 ctor = targetType.GetConstructors().FirstOrDefault(c => c.IsDefined(typeof(SelectedConstructorAttribute), true)); 242 243 if (ctor == null) 244 { 245 //2、参数最多的 246 ctor = targetType.GetConstructors().OrderByDescending(c => c.GetParameters().Length).First(); 247 } 248 249 #endregion 250 251 #region 核心创建对象代码 252 253 IList<object> parameters = new List<object>(); 254 var values = _Parameters.ContainsKey(keyword) ? _Parameters[keyword] : null; 255 int index = 0; 256 foreach (var parameter in ctor.GetParameters()) 257 { 258 if (values != null && values.Length > 0 && parameter.IsDefined(typeof(ConstantPatameterAttribute), true)) 259 { 260 parameters.Add(values[index++]); 261 } 262 else 263 { 264 var parameterType = parameter.ParameterType; 265 var instance = Create(parameterType, serviceName); 266 parameters.Add(instance); 267 } 268 } 269 object oIntance = Activator.CreateInstance(targetType, parameters.ToArray()); 270 271 #endregion 272 273 #region 属性注入 274 275 Type propertyType = null; 276 foreach (var property in targetType.GetProperties().Where(p => p.IsDefined(typeof(InjectionPropertyAttribute), true))) 277 { 278 propertyType = property.PropertyType; 279 var propInstance = Create(propertyType); 280 property.SetValue(oIntance, propInstance); 281 } 282 283 #endregion 284 285 #region 方法注入 286 287 foreach (var methodInfo in targetType.GetMethods().Where(p => p.IsDefined(typeof(InjectionMethodAttribute), true))) 288 { 289 IList<object> methodParameters = new List<object>(); 290 values = _Parameters.ContainsKey(keyword) ? _Parameters[keyword] : null; 291 index = 0; 292 foreach (var parameter in methodInfo.GetParameters()) 293 { 294 if (values != null && values.Length > 0 && parameter.IsDefined(typeof(ConstantPatameterAttribute))) 295 { 296 methodParameters.Add(values[index++]); 297 } 298 else 299 { 300 var methodParaType = parameter.ParameterType; 301 var paraInstance = Create(methodParaType, serviceName); 302 methodParameters.Add(paraInstance); 303 } 304 } 305 methodInfo.Invoke(oIntance, methodParameters.ToArray()); 306 } 307 308 #endregion 309 310 #region 生命周期 311 312 switch (lifetime) 313 { 314 case ServiceLifetime.Transient: 315 break; 316 case ServiceLifetime.Singleton: 317 if (_Container[keyword].SingletonInstance == null) 318 { 319 _Container[keyword].SingletonInstance = oIntance; 320 } 321 break; 322 case ServiceLifetime.Scoped: 323 if (!_ScopedContainer.ContainsKey(keyword)) 324 { 325 _ScopedContainer.Add(keyword, oIntance); 326 } 327 break; 328 case ServiceLifetime.PerThread: 329 CallContext.SetData($"{keyword}{Thread.CurrentThread.ManagedThreadId}", oIntance); 330 break; 331 default: 332 break; 333 } 334 335 #endregion 336 337 return oIntance; 338 } 339 } 340 }
当然了,还有一些其他的辅助类型,这么大的框架,还是要需要一些辅助类型的,接下来我们一一介绍。
2、ConstantPatameterAttribute类型
该类型是一个标记特性,用于标注不需要注入而进行传递的参数,可以使用该属性。
1 using System; 2 3 namespace PatrickLiu.NetCore50.IOCFramework.Container 4 { 5 /// <summary> 6 /// 该类型定义了在服务初始化的时候需要从外界出入的参数,如果参数被标注,则说明改参数所需要的参数从外界传入。该类型是密封类型,不可以被继承。 7 /// </summary> 8 [AttributeUsage(AttributeTargets.Parameter|AttributeTargets.GenericParameter,AllowMultiple =false,Inherited =true)] 9 public sealed class ConstantPatameterAttribute:Attribute 10 { 11 } 12 }
3、InjectionMethodAttribute 类型
该类型也是一个标记特性,用于标记方法,可以通过方法实现注入。
1 using System; 2 3 namespace PatrickLiu.NetCore50.IOCFramework.Container 4 { 5 /// <summary> 6 /// 该类型定义了方法注入的特性类型,该类型是密封类型,不可以被继承。它也是一个标识类型。 7 /// </summary> 8 [AttributeUsage(AttributeTargets.Method,AllowMultiple =false,Inherited =true)] 9 public sealed class InjectionMethodAttribute:Attribute 10 { 11 } 12 }
4、InjectionPropertyAttribute 类型。
该类型也是一个标记特性,用于标记正在属性上,可以通过属性实现注入。
1 using System; 2 3 namespace PatrickLiu.NetCore50.IOCFramework.Container 4 { 5 /// <summary> 6 /// 该特性是一个实现属性注入的特性类,该类型是密封的。它是一个标识属性。 7 /// </summary> 8 [AttributeUsage(AttributeTargets.Property, AllowMultiple = false, Inherited = true)] 9 public sealed class InjectionPropertyAttribute : Attribute 10 { 11 } 12 }
5、SelectedConstructorAttribute 类型
在我们构建类型实例的时候,可以通过该特性选择通过哪个构造函数创建实例。默认情况是选择参数最多的构造函数,也可以通过该特性选择构造函数。
1 using System; 2 3 namespace PatrickLiu.NetCore50.IOCFramework.Container 4 { 5 /// <summary> 6 /// 选择构造函数。 7 /// </summary> 8 [AttributeUsage(AttributeTargets.Constructor, AllowMultiple = false, Inherited = true)] 9 public sealed class SelectedConstructorAttribute : Attribute 10 { 11 } 12 }
6、ServiceLifetime 枚举类型。
我们可以实现对注册服务的生命周期的管理,类型简单,不多说了。
1 namespace PatrickLiu.NetCore50.IOCFramework.Container 2 { 3 /// <summary> 4 /// 服务的生命周期。 5 /// </summary> 6 public enum ServiceLifetime 7 { 8 /// <summary> 9 /// 瞬时服务实例。 10 /// </summary> 11 Transient, 12 13 /// <summary> 14 /// 单例服务实例。 15 /// </summary> 16 Singleton, 17 18 /// <summary> 19 /// 作用域服务实例。 20 /// </summary> 21 Scoped, 22 23 /// <summary> 24 /// 线程服务实例。 25 /// </summary> 26 PerThread 27 } 28 }
7、ServiceMetadata 类型。
用于定义注册服务的对象。
1 using System; 2 3 namespace PatrickLiu.NetCore50.IOCFramework.Container 4 { 5 /// <summary> 6 /// 该类型定义了注册服务的元数据。 7 /// </summary> 8 public sealed class ServiceMetadata 9 { 10 /// <summary> 11 /// 获取或者设置注册服务的类型。 12 /// </summary> 13 public Type ServiceType { get; set; } 14 15 /// <summary> 16 /// 获取或者设置注册服务的生命周期。 17 /// </summary> 18 public ServiceLifetime Lifetime { get; set; } 19 20 /// <summary> 21 /// 获取或者设置单件的服务实例。 22 /// </summary> 23 public Object SingletonInstance { get; set; } 24 } 25 }
8、CallContext类型。
在NetCore 环境中,没有CallContext 类型,所以只能自己实现一个,可以实现基于线程来管理注册服务的生命周期。
1 using System.Collections.Concurrent; 2 using System.Threading; 3 4 namespace PatrickLiu.NetCore50.IOCFramework.Container 5 { 6 /// <summary> 7 /// Provides a way to set contextual data that flows with the call and async context of a test or invocation. 8 /// </summary> 9 public static class CallContext 10 { 11 private static ConcurrentDictionary<string, AsyncLocal<object>> state = new ConcurrentDictionary<string, AsyncLocal<object>>(); 12 13 /// <summary> 14 /// Stores a given object and associates it with the specified name. 15 /// </summary> 16 /// <param name="name">The name with which to associate the new item in the call context.</param> 17 /// <param name="data">The object to store in the call context.</param> 18 public static void SetData(string name, object data) => 19 state.GetOrAdd(name, _ => new AsyncLocal<object>()).Value = data; 20 21 /// <summary> 22 /// Retrieves an object with the specified name from the <see cref="CallContext"/>. 23 /// </summary> 24 /// <param name="name">The name of the item in the call context.</param> 25 /// <returns>The object in the call context associated with the specified name, or <see langword="null"/> if not found.</returns> 26 public static object GetData(string name) => 27 state.TryGetValue(name, out AsyncLocal<object> data) ? data.Value : null; 28 } 29 30 /// <summary> 31 /// 可以测试 32 /// </summary> 33 /// <typeparam name="T"></typeparam> 34 public static class CallContext<T> 35 { 36 static ConcurrentDictionary<string, AsyncLocal<T>> state = new ConcurrentDictionary<string, AsyncLocal<T>>(); 37 38 /// <summary> 39 /// Stores a given object and associates it with the specified name. 40 /// </summary> 41 /// <param name="name">The name with which to associate the new item in the call context.</param> 42 /// <param name="data">The object to store in the call context.</param> 43 public static void SetData(string name, T data) => 44 state.GetOrAdd(name, _ => new AsyncLocal<T>()).Value = data; 45 46 /// <summary> 47 /// Retrieves an object with the specified name from the <see cref="CallContext"/>. 48 /// </summary> 49 /// <typeparam name="T">The type of the data being retrieved. Must match the type used when the <paramref name="name"/> was set via <see cref="SetData{T}(string, T)"/>.</typeparam> 50 /// <param name="name">The name of the item in the call context.</param> 51 /// <returns>The object in the call context associated with the specified name, or a default value for <typeparamref name="T"/> if none is found.</returns> 52 public static T GetData(string name) => 53 state.TryGetValue(name, out AsyncLocal<T> data) ? data.Value : default(T); 54 } 55 }
三、测试代码
我们为了更好的测试我们写的IOC容器,我另外建立两个独立的类库项目和一个控制台应用程序。当然了,引用关系别忘记了。
1、我们定义的接口类库,里面包含了测试用到的所有接口类型。很简单,不多说。
以下就是我们接口的代码了。
1 /// <summary> 2 /// ServiceA的服务接口 3 /// </summary> 4 public interface IServiceA 5 { 6 void Show(); 7 }
1 public interface IServiceB 2 { 3 void Show(); 4 }
1 public interface IServiceC 2 { 3 void Show(); 4 }
1 public interface IServiceD 2 { 3 void Show(); 4 }
1 public interface IServiceE 2 { 3 void Show(); 4 }
1 public interface IServiceF 2 { 3 void Show(); 4 }
2、第一步我们定义了接口类库,这里我们定义实现了接口类库的服务类库,很简单,不多说。
以下是实现代码,很简单,不多说。
1 /// <summary> 2 /// 自定义类型的服务。 3 /// </summary> 4 public class MyServiceA : IServiceA 5 { 6 public MyServiceA() 7 { 8 Console.WriteLine("MyServiceA is Created"); 9 } 10 11 /// <summary> 12 /// 方法执行 13 /// </summary> 14 public void Show() 15 { 16 Console.WriteLine("MyServiceA-show()"); 17 } 18 }
1 /// <summary> 2 /// 自定义类型服务第二版本。 3 /// </summary> 4 public sealed class MyServiceA2 : IServiceA 5 { 6 private IServiceF _IServiceF; 7 8 /// <summary> 9 /// 构造函数 10 /// </summary> 11 public MyServiceA2() 12 { 13 Console.WriteLine("MyServiceA2 is created"); 14 } 15 16 /// <summary> 17 /// 方法注入。 18 /// </summary> 19 /// <param name="service"></param> 20 [InjectionMethod] 21 public void MethodInjection(IServiceF service) 22 { 23 _IServiceF = service; 24 } 25 26 /// <summary> 27 /// 方法执行。 28 /// </summary> 29 public void Show() 30 { 31 Console.WriteLine("MyServiceA2--Show()"); 32 } 33 }
1 public class MyServiceA3 : IServiceA 2 { 3 /// <summary> 4 /// 5 /// </summary> 6 /// <param name="age"></param> 7 /// <param name="name"></param> 8 /// <param name="school"></param> 9 public MyServiceA3([ConstantPatameter]int age, [ConstantPatameter] string name, [ConstantPatameter] string school) 10 { 11 Console.WriteLine($"{age}{name}{school} MyServiceA3 is created"); 12 } 13 14 15 public void Show() 16 { 17 Console.WriteLine("MyServiceA3-Show() is executed!"); 18 } 19 }
1 public class MyServiceA4 : IServiceA 2 { 3 private IServiceF _IServiceF; 4 5 public MyServiceA4() 6 { 7 Console.WriteLine(""); 8 } 9 10 /// <summary> 11 /// 方法注入 12 /// </summary> 13 /// <param name="service">注入服务</param> 14 /// <param name="age"></param> 15 /// <param name="name"></param> 16 [InjectionMethod] 17 public void MethodInjection(IServiceF service,[ConstantPatameter]int age,[ConstantPatameter]string name) 18 { 19 _IServiceF = service; 20 Console.WriteLine($"{name} 今年 {age} 岁了。"); 21 } 22 23 public void Show() 24 { 25 Console.WriteLine("MyServiceA4--show() executing"); 26 } 27 }
1 /// <summary> 2 /// 3 /// </summary> 4 public class MyServiceB : IServiceB 5 { 6 /// <summary> 7 /// 8 /// </summary> 9 /// <param name="serviceC"></param> 10 /// <param name="serviceE"></param> 11 public MyServiceB(IServiceC serviceC,IServiceE serviceE) 12 { 13 Console.WriteLine("MyServiceB is created"); 14 } 15 16 /// <summary> 17 /// 18 /// </summary> 19 public void Show() 20 { 21 Console.WriteLine("MyServiceB-Show()"); 22 } 23 }
1 /// <summary> 2 /// 3 /// </summary> 4 public class MyServiceC : IServiceC 5 { 6 /// <summary> 7 /// 8 /// </summary> 9 /// <param name="serviceD"></param> 10 public MyServiceC(IServiceD serviceD) 11 { 12 Console.WriteLine("MyServiceC is created"); 13 } 14 15 /// <summary> 16 /// 17 /// </summary> 18 public void Show() 19 { 20 Console.WriteLine("MyServiceC-Show()"); 21 } 22 }
1 /// <summary> 2 /// 自定义类型的服务。 3 /// </summary> 4 public class MyServiceD : IServiceD 5 { 6 /// <summary> 7 /// 构造函数 8 /// </summary> 9 public MyServiceD() 10 { 11 Console.WriteLine("MyServiceD is created"); 12 } 13 14 /// <summary> 15 /// 方法执行。 16 /// </summary> 17 public void Show() 18 { 19 Console.WriteLine("MyServiceD--show()"); 20 } 21 }
1 /// <summary> 2 /// 自定义服务类型。 3 /// </summary> 4 public class MyServiceE : IServiceE 5 { 6 /// <summary> 7 /// 构造函数 8 /// </summary> 9 public MyServiceE() 10 { 11 Console.WriteLine("MyServiceE is created"); 12 } 13 14 /// <summary> 15 /// 属性注入 16 /// </summary> 17 [InjectionProperty] 18 public IServiceF ServiceF { get; set; } 19 20 /// <summary> 21 /// 方法执行。 22 /// </summary> 23 public void Show() 24 { 25 Console.WriteLine("MyServiceE-Show()"); 26 } 27 }
1 /// <summary> 2 /// 自定义类型服务。 3 /// </summary> 4 public sealed class MyServiceF : IServiceF 5 { 6 /// <summary> 7 /// 构造函数 8 /// </summary> 9 public MyServiceF() 10 { 11 Console.WriteLine("MyServiceF is created!"); 12 } 13 14 /// <summary> 15 /// 方法执行。 16 /// </summary> 17 public void Show() 18 { 19 Console.WriteLine("MyServiceF--Show()"); 20 } 21 }
3、这个代码就是我们控制台项目,用来做测试的,很简单,不多说了。
1 class Program 2 { 3 static void Main(string[] args) 4 { 5 //最简单版本 6 { 7 PatrickContainer container = new PatrickContainer(); 8 container.Register<IServiceA, MyServiceA>(); 9 10 var instance = container.Resolve<IServiceA>(); 11 instance.Show(); 12 } 13 //可以多层依赖,可以包含属性注入 14 { 15 PatrickContainer container = new PatrickContainer(); 16 container.Register<IServiceA, MyServiceA>(); 17 container.Register<IServiceB, MyServiceB>(); 18 container.Register<IServiceC, MyServiceC>(); 19 container.Register<IServiceD, MyServiceD>(); 20 container.Register<IServiceE, MyServiceE>(); 21 container.Register<IServiceF, MyServiceF>(); 22 23 var instance = container.Resolve<IServiceB>(); 24 instance.Show(); 25 } 26 //单接口多实例,也包含方法注入 27 { 28 PatrickContainer container = new PatrickContainer(); 29 container.Register<IServiceA, MyServiceA>("A"); 30 container.Register<IServiceA, MyServiceA2>("A2"); 31 container.Register<IServiceF, MyServiceF>(); 32 33 var instance = container.Resolve<IServiceA>("A"); 34 instance.Show(); 35 instance = container.Resolve<IServiceA>("A2"); 36 instance.Show(); 37 } 38 //构造函数参数、方法参数 39 { 40 PatrickContainer container = new PatrickContainer(); 41 42 container.Register<IServiceA, MyServiceA3>(20,"zhangfei","涞源第一中学"); 43 44 var instance = container.Resolve<IServiceA>(); 45 instance.Show(); 46 } 47 { 48 PatrickContainer container = new PatrickContainer(); 49 50 container.Register<IServiceA, MyServiceA4>(20, "张飞"); 51 container.Register<IServiceF, MyServiceF>(); 52 53 var instance = container.Resolve<IServiceA>(); 54 instance.Show(); 55 } 56 //声明周期 57 { 58 //单例 59 PatrickContainer container = new PatrickContainer(); 60 container.Register<IServiceA, MyServiceA>(ServiceLifetime.Singleton); 61 62 63 var instance = container.Resolve<IServiceA>(); 64 var instance2 = container.Resolve<IServiceA>(); 65 66 Console.WriteLine(Object.ReferenceEquals(instance,instance2));//True 67 } 68 // 69 { 70 //瞬时 71 PatrickContainer container = new PatrickContainer(); 72 container.Register<IServiceA, MyServiceA>(ServiceLifetime.Transient); 73 74 75 var instance = container.Resolve<IServiceA>(); 76 var instance2 = container.Resolve<IServiceA>(); 77 78 Console.WriteLine(Object.ReferenceEquals(instance, instance2));//False 79 } 80 { 81 //作用域 82 PatrickContainer container = new PatrickContainer(); 83 container.Register<IServiceA, MyServiceA>(ServiceLifetime.Scoped); 84 85 86 var instance = container.Resolve<IServiceA>(); 87 var instance2 = container.Resolve<IServiceA>(); 88 89 Console.WriteLine(Object.ReferenceEquals(instance, instance2));//True 90 91 var container2 = container.CreateScoped(); 92 var objedd=container2.Resolve<IServiceA>(); 93 var objedd2=container2.Resolve<IServiceA>(); 94 95 /Console.WriteLine(Object.ReferenceEquals(objedd, objedd2));//True 96 97 Console.WriteLine(Object.ReferenceEquals(instance, objedd2));//False 98 Console.ReadLine(); 99 } 100 { 101 //线程 102 PatrickContainer container = new PatrickContainer(); 103 container.Register<IServiceA, MyServiceA>(ServiceLifetime.PerThread); 104 105 IServiceA instance = null; 106 IServiceA instance2 = null; 107 IServiceA instance3 = null; 108 IServiceA instance4 = null; 109 IServiceA instance5 = null; 110 IServiceA instance6 = null; 111 112 Task.Run(()=> { 113 Console.WriteLine($"instance,当前线程的ID:{Thread.CurrentThread.ManagedThreadId}"); 114 instance = container.Resolve<IServiceA>(); 115 }); 116 117 Task.Run(() => { 118 Console.WriteLine($"instance2,当前线程的ID:{Thread.CurrentThread.ManagedThreadId}"); 119 instance2 = container.Resolve<IServiceA>(); 120 }); 121 122 Task.Run(() => { 123 Console.WriteLine($"instance3 和 instance4,当前线程的ID:{Thread.CurrentThread.ManagedThreadId}"); 124 instance3 = container.Resolve<IServiceA>(); 125 instance4 = container.Resolve<IServiceA>(); 126 }); 127 128 Task.Run(() => { 129 Console.WriteLine($"instance5,当前线程的ID:{Thread.CurrentThread.ManagedThreadId}"); 130 instance5 = container.Resolve<IServiceA>(); 131 }).ContinueWith(t=> { 132 Console.WriteLine($"instance6,当前线程的ID:{Thread.CurrentThread.ManagedThreadId}"); 133 instance6 = container.Resolve<IServiceA>(); 134 }); 135 136 Thread.Sleep(1000); 137 138 Console.WriteLine(Object.ReferenceEquals(instance, instance2));//False 139 Console.WriteLine(Object.ReferenceEquals(instance, instance3));//False 140 Console.WriteLine(Object.ReferenceEquals(instance, instance4));//False 141 Console.WriteLine(Object.ReferenceEquals(instance2, instance3));//False 142 Console.WriteLine(Object.ReferenceEquals(instance2, instance4));//False 143 Console.WriteLine(Object.ReferenceEquals(instance3, instance4));//True 144 145 Console.WriteLine(Object.ReferenceEquals(instance5, instance6));//False 146 } 147 148 Console.Read(); 149 } 150 }
四、结束
好了,今天就写到这里了,实话实说,这个有难度吗?其实没什么难度。这些代码都是可以直接使用的,我经过测试的,(我也有可能没有测试到的),如果大家感觉不错,可以拿去使用,好好的测试一下,也可以增加自己的东西,功能挺强大的,使用挺方便的。不忘初心,继续努力。
Recommend
About Joyk
Aggregate valuable and interesting links.
Joyk means Joy of geeK