一、介紹
1、介紹
最近無聊,也沒什么事做,沒事做總是要給自己找點事情做吧,畢竟人的生活在與折騰。于是,決定自己手動寫一個 IOC 的框架。我們知道在 NetCore 的版本里面已經(jīng)內(nèi)置了 IOC 容器,它就是 ServiceCollection,一般情況下,該容器還是夠用的,但是有時候還會有力不從心的時候,比如:我想要實現(xiàn)屬性注入或者方法注入,NetCore 內(nèi)置的框架就不可以實現(xiàn)。還有情況是,我們要實現(xiàn)對同一接口的多實例注入也沒辦法實現(xiàn)。當(dāng)然還有其他情況,比如,沒有實現(xiàn) AOP 的功能。最近正好無事可做,正好利用這段時間,自己親手寫一套 IOC 的框架,當(dāng)然了,要重寫,肯定要比 NetCore 內(nèi)置的要強,否則,也就沒有寫的必要了,說干就干。
2、開發(fā)環(huán)境
1)、操作系統(tǒng):windows 10 專業(yè)版本。
2)、開發(fā)工具:Visual Studio 2019 社區(qū)版,16.8.3
3)、開發(fā)語言:C#
4)、框架版本:Net 5.0,該版本是跨平臺版本,但是不是長期版本,6.0 是 LTS 版本。
3、實現(xiàn)目標(biāo)
1)、該框架可以實現(xiàn)構(gòu)造函數(shù)注入。
2)、該框架可以實現(xiàn)方法注入。
3)、該框架可以實現(xiàn)屬性注入。
4)、該框架可以實現(xiàn)無限層級激活。
5)、該框架可以實現(xiàn)注冊服務(wù)的多種聲明周期,分別是:Transient,Singleton,Scoped,PerThread
6)、該框架可以實現(xiàn)針對同一接口的多實例注冊。
7)、當(dāng)一個類型在實例化的時候可以增加參數(shù)。
以上就是該框架的目標(biāo),應(yīng)該還不錯吧。畢竟我們自己手寫了框架代碼,讓我們會更加了解 IOC 的定義和實現(xiàn)。
二、手寫框架
1、我先把該框架的主要類型的代碼貼出來,這個類型是核心類型,實現(xiàn)了我們上面定義的目標(biāo)。
首先、我們?yōu)?IOC 容器定義接口,面向接口編程嘛,可不要忘記了,所以,我們先頂一個接口,類型名稱:ICustomContainer。
1 /// <summary>
2 /// 我們定義的 IOC 容器抽象基類型,它定義了 IOC 容器的核心功能。
3 /// </summary>
4 public interface ICustomContainer
5 {
6 /// <summary>
7 /// 提供服務(wù)的名稱和參數(shù)構(gòu)建實例以 TFrom 類型注冊 TTo 實例。
8 /// </summary>
9 /// <typeparam name="TFrom">TTo 的基類類型。</typeparam>
10 /// <typeparam name="TTo">TFrom 的子類類型。</typeparam>
11 /// <param name="serviceName">要注冊服務(wù)的名稱。</param>
12 /// <param name="lifetime">要注冊的服務(wù)的生命周期。</param>
13 /// <param name="parameterValues">要注冊的服務(wù)在構(gòu)建實例時需要的非注入?yún)?shù)。</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 }
再者,就是該接口的實現(xiàn)類型,該類型也是該容器的核心代碼。代碼不是很難,大家直接看吧。
類型名稱: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容器實現(xiàn)。
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 /// 可以創(chuàng)建子作用域。
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 /// 通過是有構(gòu)造函數(shù)初始化容器。
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">要注冊的服務(wù)的生命周期。</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 /// 提供服務(wù)構(gòu)建實例所需參數(shù)來以 TFrom 類型注冊 TTo 實例。
75 /// </summary>
76 /// <typeparam name="TFrom">TTo 的基類類型</typeparam>
77 /// <typeparam name="TTo">TFrom 的子類類型。</typeparam>
78 /// <param name="parameterValues">要注冊的服務(wù)在構(gòu)建實例時需要的非注入?yún)?shù)。</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 /// 提供服務(wù)的名稱構(gòu)建實例來以 TFrom 類型注冊 TTo 實例。
86 /// </summary>
87 /// <typeparam name="TFrom">TTo 的基類類型</typeparam>
88 /// <typeparam name="TTo">TFrom 的子類類型。</typeparam>
89 /// <param name="serviceName">要注冊服務(wù)的名稱。</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 /// 提供服務(wù)的名稱構(gòu)建實例來以 TFrom 類型注冊 TTo 實例。
97 /// </summary>
98 /// <typeparam name="TFrom">TTo 的基類類型</typeparam>
99 /// <typeparam name="TTo">TFrom 的子類類型。</typeparam>
100 /// <param name="serviceName">要注冊服務(wù)的名稱。</param>
101 /// <param name="lifetime">要注冊的服務(wù)的生命周期。</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 /// 提供服務(wù)的名稱和參數(shù)構(gòu)建實例以 TFrom 類型注冊 TTo 實例。
109 /// </summary>
110 /// <typeparam name="TFrom">TTo 的基類類型</typeparam>
111 /// <typeparam name="TTo">TFrom 的子類類型。</typeparam>
112 /// <param name="serviceName">要注冊服務(wù)的名稱。</param>
113 /// <param name="lifetime">要注冊的服務(wù)的生命周期。</param>
114 /// <param name="parameterValues">要注冊的服務(wù)在構(gòu)建實例時需要的非注入?yún)?shù)。</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 /// 通過遞歸實現(xiàn)解析實例對象。
164 /// </summary>
165 /// <param name="baseType">服務(wù)的基類型。</param>
166 /// <param name="serviceName">服務(wù)實例的名稱。</param>
167 /// <returns></returns>
168 private object Create(Type baseType, string serviceName = null)
169 {
170 #region 處理關(guān)鍵字
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 選擇構(gòu)造函數(shù)
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、參數(shù)最多的
246 ctor = targetType.GetConstructors().OrderByDescending(c => c.GetParameters().Length).First();
247 }
248
249 #endregion
250
251 #region 核心創(chuàng)建對象代碼
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 }
當(dāng)然了,還有一些其他的輔助類型,這么大的框架,還是要需要一些輔助類型的,接下來我們一一介紹。
2、
ConstantPatameterAttribute類型
該類型是一個標(biāo)記特性,用于標(biāo)注不需要注入而進行傳遞的參數(shù),可以使用該屬性。
1 using System;
2
3 namespace PatrickLiu.NetCore50.IOCFramework.Container
4 {
5 /// <summary>
6 /// 該類型定義了在服務(wù)初始化的時候需要從外界出入的參數(shù),如果參數(shù)被標(biāo)注,則說明改參數(shù)所需要的參數(shù)從外界傳入。該類型是密封類型,不可以被繼承。
7 /// </summary>
8 [AttributeUsage(AttributeTargets.Parameter|AttributeTargets.GenericParameter,AllowMultiple =false,Inherited =true)]
9 public sealed class ConstantPatameterAttribute:Attribute
10 {
11 }
12 }
3、InjectionMethodAttribute 類型
該類型也是一個標(biāo)記特性,用于標(biāo)記方法,可以通過方法實現(xiàn)注入。
1 using System;
2
3 namespace PatrickLiu.NetCore50.IOCFramework.Container
4 {
5 /// <summary>
6 /// 該類型定義了方法注入的特性類型,該類型是密封類型,不可以被繼承。它也是一個標(biāo)識類型。
7 /// </summary>
8 [AttributeUsage(AttributeTargets.Method,AllowMultiple =false,Inherited =true)]
9 public sealed class InjectionMethodAttribute:Attribute
10 {
11 }
12 }
4、
InjectionPropertyAttribute 類型。
該類型也是一個標(biāo)記特性,用于標(biāo)記正在屬性上,可以通過屬性實現(xiàn)注入。
1 using System;
2
3 namespace PatrickLiu.NetCore50.IOCFramework.Container
4 {
5 /// <summary>
6 /// 該特性是一個實現(xiàn)屬性注入的特性類,該類型是密封的。它是一個標(biāo)識屬性。
7 /// </summary>
8 [AttributeUsage(AttributeTargets.Property, AllowMultiple = false, Inherited = true)]
9 public sealed class InjectionPropertyAttribute : Attribute
10 {
11 }
12 }
5、
SelectedConstructorAttribute 類型
在我們構(gòu)建類型實例的時候,可以通過該特性選擇通過哪個構(gòu)造函數(shù)創(chuàng)建實例。默認情況是選擇參數(shù)最多的構(gòu)造函數(shù),也可以通過該特性選擇構(gòu)造函數(shù)。
1 using System;
2
3 namespace PatrickLiu.NetCore50.IOCFramework.Container
4 {
5 /// <summary>
6 /// 選擇構(gòu)造函數(shù)。
7 /// </summary>
8 [AttributeUsage(AttributeTargets.Constructor, AllowMultiple = false, Inherited = true)]
9 public sealed class SelectedConstructorAttribute : Attribute
10 {
11 }
12 }
6、ServiceLifetime 枚舉類型。
我們可以實現(xiàn)對注冊服務(wù)的生命周期的管理,類型簡單,不多說了。
1 namespace PatrickLiu.NetCore50.IOCFramework.Container
2 {
3 /// <summary>
4 /// 服務(wù)的生命周期。
5 /// </summary>
6 public enum ServiceLifetime
7 {
8 /// <summary>
9 /// 瞬時服務(wù)實例。
10 /// </summary>
11 Transient,
12
13 /// <summary>
14 /// 單例服務(wù)實例。
15 /// </summary>
16 Singleton,
17
18 /// <summary>
19 /// 作用域服務(wù)實例。
20 /// </summary>
21 Scoped,
22
23 /// <summary>
24 /// 線程服務(wù)實例。
25 /// </summary>
26 PerThread
27 }
28 }
7、ServiceMetadata 類型。
用于定義注冊服務(wù)的對象。
1 using System;
2
3 namespace PatrickLiu.NetCore50.IOCFramework.Container
4 {
5 /// <summary>
6 /// 該類型定義了注冊服務(wù)的元數(shù)據(jù)。
7 /// </summary>
8 public sealed class ServiceMetadata
9 {
10 /// <summary>
11 /// 獲取或者設(shè)置注冊服務(wù)的類型。
12 /// </summary>
13 public Type ServiceType { get; set; }
14
15 /// <summary>
16 /// 獲取或者設(shè)置注冊服務(wù)的生命周期。
17 /// </summary>
18 public ServiceLifetime Lifetime { get; set; }
19
20 /// <summary>
21 /// 獲取或者設(shè)置單件的服務(wù)實例。
22 /// </summary>
23 public Object SingletonInstance { get; set; }
24 }
25 }
8、CallContext類型。
在NetCore 環(huán)境中,沒有CallContext 類型,所以只能自己實現(xiàn)一個,可以實現(xiàn)基于線程來管理注冊服務(wù)的生命周期。
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 }
三、測試代碼
我們?yōu)榱烁玫臏y試我們寫的IOC容器,我另外建立兩個獨立的類庫項目和一個控制臺應(yīng)用程序。當(dāng)然了,引用關(guān)系別忘記了。
1、我們定義的接口類庫,里面包含了測試用到的所有接口類型。很簡單,不多說。
以下就是我們接口的代碼了。
1 /// <summary>
2 /// ServiceA的服務(wù)接口
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、第一步我們定義了接口類庫,這里我們定義實現(xiàn)了接口類庫的服務(wù)類庫,很簡單,不多說。
以下是實現(xiàn)代碼,很簡單,不多說。
1 /// <summary>
2 /// 自定義類型的服務(wù)。
3 /// </summary>
4 public class MyServiceA : IServiceA
5 {
6 public MyServiceA()
7 {
8 Console.WriteLine("MyServiceA is Created");
9 }
10
11 /// <summary>
12 /// 方法執(zhí)行
13 /// </summary>
14 public void Show()
15 {
16 Console.WriteLine("MyServiceA-show()");
17 }
18 }
1 /// <summary>
2 /// 自定義類型服務(wù)第二版本。
3 /// </summary>
4 public sealed class MyServiceA2 : IServiceA
5 {
6 private IServiceF _IServiceF;
7
8 /// <summary>
9 /// 構(gòu)造函數(shù)
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 /// 方法執(zhí)行。
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">注入服務(wù)</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 /// 自定義類型的服務(wù)。
3 /// </summary>
4 public class MyServiceD : IServiceD
5 {
6 /// <summary>
7 /// 構(gòu)造函數(shù)
8 /// </summary>
9 public MyServiceD()
10 {
11 Console.WriteLine("MyServiceD is created");
12 }
13
14 /// <summary>
15 /// 方法執(zhí)行。
16 /// </summary>
17 public void Show()
18 {
19 Console.WriteLine("MyServiceD--show()");
20 }
21 }
1 /// <summary>
2 /// 自定義服務(wù)類型。
3 /// </summary>
4 public class MyServiceE : IServiceE
5 {
6 /// <summary>
7 /// 構(gòu)造函數(shù)
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 /// 方法執(zhí)行。
22 /// </summary>
23 public void Show()
24 {
25 Console.WriteLine("MyServiceE-Show()");
26 }
27 }
1 /// <summary>
2 /// 自定義類型服務(wù)。
3 /// </summary>
4 public sealed class MyServiceF : IServiceF
5 {
6 /// <summary>
7 /// 構(gòu)造函數(shù)
8 /// </summary>
9 public MyServiceF()
10 {
11 Console.WriteLine("MyServiceF is created!");
12 }
13
14 /// <summary>
15 /// 方法執(zhí)行。
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 //構(gòu)造函數(shù)參數(shù)、方法參數(shù)
39 {
40 PatrickContainer container = new PatrickContainer();
41
42 container.Register<IServiceA, MyServiceA3>(20,"zhangfei","淶源第一中學(xué)");
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,當(dāng)前線程的ID:{Thread.CurrentThread.ManagedThreadId}");
114 instance = container.Resolve<IServiceA>();
115 });
116
117 Task.Run(() => {
118 Console.WriteLine($"instance2,當(dāng)前線程的ID:{Thread.CurrentThread.ManagedThreadId}");
119 instance2 = container.Resolve<IServiceA>();
120 });
121
122 Task.Run(() => {
123 Console.WriteLine($"instance3 和 instance4,當(dāng)前線程的ID:{Thread.CurrentThread.ManagedThreadId}");
124 instance3 = container.Resolve<IServiceA>();
125 instance4 = container.Resolve<IServiceA>();
126 });
127
128 Task.Run(() => {
129 Console.WriteLine($"instance5,當(dāng)前線程的ID:{Thread.CurrentThread.ManagedThreadId}");
130 instance5 = container.Resolve<IServiceA>();
131 }).ContinueWith(t=> {
132 Console.WriteLine($"instance6,當(dāng)前線程的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 }
四、結(jié)束
好了,今天就寫到這里了,實話實說,這個有難度嗎?其實沒什么難度。這些代碼都是可以直接使用的,我經(jīng)過測試的,(我也有可能沒有測試到的),如果大家感覺不錯,可以拿去使用,好好的測試一下,也可以增加自己的東西,功能挺強大的,使用挺方便的。不忘初心,繼續(xù)努力。
天下國家,可均也;爵祿,可辭也;白刃,可蹈也;中庸不可能也