您当前的位置:首页 > 电脑百科 > 程序开发 > 容器

让我手把手教你写一个强大、方便使用的 IOC 容器

时间:2021-07-20 09:55:40  来源:  作者:JAVA互联搬砖工人

一、介绍

    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、我们定义的接口类库,里面包含了测试用到的所有接口类型。很简单,不多说。

让我手把手教你写一个强大、方便使用的 IOC 容器

 

 

         以下就是我们接口的代码了。        

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、第一步我们定义了接口类库,这里我们定义实现了接口类库的服务类库,很简单,不多说。

让我手把手教你写一个强大、方便使用的 IOC 容器

 

        以下是实现代码,很简单,不多说。
        

 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     }

 

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

天下国家,可均也;爵禄,可辞也;白刃,可蹈也;中庸不可能也



Tags: IOC 容器   点击:()  评论:()
声明:本站部分内容及图片来自互联网,转载是出于传递更多信息之目的,内容观点仅代表作者本人,如有任何标注错误或版权侵犯请与我们联系(Email:2595517585@qq.com),我们将及时更正、删除,谢谢。
▌相关推荐
一、介绍    1、介绍        最近无聊,也没什么事做,没事做总是要给自己找点事情做吧,毕竟人的生活在与折腾。于是,决定自己手动写一个 IOC 的框架。我们知道在 Net...【详细内容】
2021-07-20  Tags: IOC 容器  点击:(80)  评论:(0)  加入收藏
▌简易百科推荐
一、为什么要搭建主从架构呢1.数据安全,可以进行数据的备份。2.读写分离,大部分的业务系统来说都是读数据多,写数据少,当访问压力过大时,可以把读请求给到从服务器。从而缓解数据...【详细内容】
2021-12-15  实战Java    Tags:Docker   点击:(10)  评论:(0)  加入收藏
在网页中渲染公式一直是泛学术工具绕不开的一个功能,最近更新产品功能,正巧遇到了这个需求,于是使用容器方式简单实现了一个相对靠谱的公式渲染服务。分享出来,希望能够帮到有类...【详细内容】
2021-12-01  编程菌zfn    Tags:Docker   点击:(10)  评论:(0)  加入收藏
1.1 docker命令直接部署1.1.1 拉取镜像docker pull wurstmeister/zookeeperdocker pull wurstmeister/kafka1.1.2 启动zookeeper容器docker run -d --name myzookeeper -p 2...【详细内容】
2021-11-15  无    Tags:docker   点击:(47)  评论:(0)  加入收藏
01 前言 顺着docker的发展,很多测试的同学也已经在测试工作上使用docker作为环境基础去进行一些自动化测试,这篇文章主要讲述我们在docker中使用浏览器进行自动化测试如果可以...【详细内容】
2021-10-29  小码哥聊软件测试    Tags:Docker   点击:(42)  评论:(0)  加入收藏
因为你懂得的原因,下载docker镜像速度非常喜感,故收集几个国内常用的docker镜像。Docker中国区官方镜像地址:https://registry.docker-cn.com网易163的镜像http://hub-mirror.c...【详细内容】
2021-10-28  抓蛙程序猿    Tags:docker   点击:(48)  评论:(0)  加入收藏
环境:Spring5.3.10通常,应用程序开发人员不需要对ApplicationContext实现类进行子类化。相反,SpringIOC容器可以通过插入特殊集成接口的实现来扩展。使用BeanPostProcessor自定...【详细内容】
2021-10-26  Java网络研发架构师    Tags:Spring   点击:(33)  评论:(0)  加入收藏
我们在很多场景下都需要做笔记,来对抗遗忘,一份好的笔记不仅能在需要的时候供我们查阅,也能帮助我们归纳整理知识提高做事效率。 目前市面上有很多云笔记软件,体验上各有不同,但...【详细内容】
2021-10-11  运维贼船    Tags:docker   点击:(61)  评论:(0)  加入收藏
1. Nacos官网Nacos Docker 快速开始2. Clone 项目git clone https://github.com/nacos-group/nacos-docker.git3. cd 到nacos-docker 路径下 直接启动即可cd nacos-dockerdo...【详细内容】
2021-09-16  程序狗爱化妆    Tags:Nacos   点击:(109)  评论:(0)  加入收藏
今天不做保姆级教程,分享奶爸常用、好用的Docker应用。有了这些Docker,Nas的可玩性会大幅提高,有时候奶爸也在想,刨去官方套件不考虑的话,Nas真的是差不多。如果小伙伴们有需要,后...【详细内容】
2021-09-03  晋升奶爸的垃圾佬    Tags:Docker   点击:(167)  评论:(0)  加入收藏
环境要求 ubuntu系统:20.04 docker版本:20.10.7 redis版本:6.0.6步骤由于我这里已经有相应的redis镜像,这里就不记录了,关于docker一些基础知识可以看我以前的笔记开启3台re...【详细内容】
2021-07-26  石老师小跟班    Tags:Redis主从复制   点击:(117)  评论:(0)  加入收藏
最新更新
栏目热门
栏目头条