一、介绍

    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 }

四、结束
    
好了,今天就写到这里了,实话实说,这个有难度吗?其实没什么难度。这些代码都是可以直接使用的,我经过测试的,(我也有可能没有测试到的),如果大家感觉不错,可以拿去使用,好好的测试一下,也可以增加自己的东西,功能挺强大的,使用挺方便的。不忘初心,继续努力。

让我手把手教你写一个强大、方便使用的 IOC 容器的更多相关文章

  1. 只有20行Javascript代码!手把手教你写一个页面模板引擎

    http://www.toobug.net/article/how_to_design_front_end_template_engine.html http://barretlee.com/webs ...

  2. 手把手教你写一个java的orm(五)

    生成sql:where 上一篇里我们实现了生成insert的sql,下面要开始实现update,delete,select的sql语句了.但是这些语句有一个比较麻烦的地方是:它们一般后面都会有wher ...

  3. 手把手教你写一个java的orm(一)

    写之前的说明 其实吧. 这个东西已经写好了,地址在:https://github.com/hjx601496320/JdbcPlus 这系列文章算是我写的过程的总结吧.(恩系列,说明我可能会写好久,╮ ...

  4. 手把手教你写一个RPC

    1.1 RPC 是什么 定义:RPC(Remote Procedure Call Protocol)--远程过程调用协议 ,RPC协议假定某些传输协议的存在,如TCP或UDP,为通信程序之间携带信息数 ...

  5. 手把手教你写一个SpringMVC框架

    一.介绍 在日常的 web 开发中,熟悉 java 的同学一定知道,Spring MVC 可以说是目前最流行的框架,之所以如此的流行,原因很简单:编程简洁.上手简单! 我记得刚开始入行的时候,最先接触 ...

  6. 手把手教你写一个RN小程序!

    时间过得真快,眨眼已经快3年了! 1.我的第一个App 还记得我14年初写的第一个iOS小程序,当时是给别人写的一个单机的相册,也是我开发的第一个完整的app,虽然功能挺少,但是耐不住心中的激动啊,现 ...

  7. 手把手教你写一个java的orm(完)

    生成sql:select 上一篇讲了怎样生成一个sql中where的一部分,之后我们要做事情就简单很多了,就只要像最开始一样的生成各种sql语句就好了,之后只要再加上我们需要的条件,一个完整的sql就 ...

  8. 手把手教你写一个java的orm(四)

    开始准备生成sql 在上一篇里,我们已经取到了我们在生成sql语句中所需要的信息,这一篇里我们开始根据class来生成我们需要的sql.在这之前我们先确认几件事情 sql里的参数我们使用占位符的形式. ...

  9. 手把手教你写一个java的orm(三)

    使用反射解析class 上一篇我们完成了class到表映射关系的建立,但是这个并不能被代码正确处理,我们还需要让程序能够正确的识别这些映射关系. 这一篇主要讲的是建立一个从class到表的模型,使我们 ...

随机推荐

  1. python批量向kafka塞数据

    python批量向kafka塞数据 from kafka import KafkaClient from kafka.producer import SimpleProducer from kafka ...

  2. Docker学习(15) Docker容器的跨主机连接

    Docker容器的跨主机连接 Docker使用网桥跨主机容器连接 Docker使用Open cSwitch实现跨主机容器连接 Docker使用weave实现跨主机容器连接

  3. 如何保证mq不丢消息

    1.消息的发送流程 一条消息从生产到被消费,将会经历3个阶段 生产阶段,Producer 新建消息,然后通过网络将消息投递给MQ Broker 存储阶段,消息将会存储在Broker端磁盘中 消费阶段, ...

  4. Deformable 可变形的DETR

    Deformable 可变形的DETR This repository is an official implementation of the paper Deformable DETR: Defo ...

  5. 向量算子优化Vector Operation Optimization

    向量算子优化Vector Operation Optimization 查看MATLAB命令View MATLAB Command 示例显示Simulink编码器 ,将生成向量的块输出,设置为标量,优 ...

  6. nvGraph-NVIDIA图形库

    nvGraph-NVIDIA图形库 数据分析是高性能计算的不断增长的应用.许多高级数据分析问题可以称为图形问题.反过来,当今许多常见的图形问题也可以称为稀疏线性代数.这是nvGraph的动机,它利用G ...

  7. WizTree——一个扫描快似Everything的硬盘空间分析工具

    虽然我平时用的主要是Linux,但是由于实际环境是win10,对于磁盘资源的控制,我主要是通过Windows自带的文件资源管理器来查看的,但是显然这个工具不够直观.于是,我也被安利过SpaceSnif ...

  8. Spring Boot WebFlux-导读

    背景 大家都知道,Spring Framework 是 Java/Spring 应用程序跨平台开发框架,也是 Java EE(Java Enterprise Edition) 轻量级框架,其 Spri ...

  9. .NET Core/.NET5/.NET6 开源项目汇总3:工作流组件

    系列目录     [已更新最新开发文章,点击查看详细] 开源项目是众多组织与个人分享的组件或项目,作者付出的心血我们是无法体会的,所以首先大家要心存感激.尊重.请严格遵守每个项目的开源协议后再使用.尊 ...

  10. Linux中Crontab的用法

    1.crontab的概念: crontab命令用于设置周期性被执行的指令.该命令从标准输入设备读取指令,并将其存放于"crontab"文件中,以供之后读取和执行.可以使用它在每天的 ...