7

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

 3 years ago
source link: https://www.cnblogs.com/PatrickLiu/p/14998785.html
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.
neoserver,ios ssh client
让我手把手教你写一个强大、方便使用的 IOC 容器

posts - 173,  comments - 414,  views -

105万

一、介绍

    1、介绍

        最近无聊,也没什么事做,没事做总是要给自己找点事情做吧,毕竟人的生活在与折腾。于是,决定自己手动写一个 IOC 的框架。我们知道在 NetCore 的版本里面已经内置了 IOC 容器,它就是 ServiceCollection,一般情况下,该容器还是够用的,但是有时候还会有力不从心的时候,比如:我想要实现属性注入或者方法注入,NetCore 内置的框架就不可以实现。还有情况是,我们要实现对同一接口的多实例注入也没办法实现。当然还有其他情况,比如,没有实现 AOP 的功能。最近正好无事可做,正好利用这段时间,自己亲手写一套 IOC 的框架,当然了,要重写,肯定要比 NetCore 内置的要强,否则,也就没有写的必要了,说干就干。

    2、开发环境

        1)、操作系统:Windows 10 专业版本。

        2)、开发工具:Visual Studio 2019 社区版,16.8.3

        3)、开发语言:C#

        4)、框架版本:Net 5.0,该版本是跨平台版本,但是不是长期版本,6.0 是 LTS 版本。

    3、实现目标

        1)、该框架可以实现构造函数注入。

        2)、该框架可以实现方法注入。

        3)、该框架可以实现属性注入。

        4)、该框架可以实现无限层级激活。

        5)、该框架可以实现注册服务的多种声明周期,分别是:Transient,Singleton,Scoped,PerThread

        6)、该框架可以实现针对同一接口的多实例注册。

        7)、当一个类型在实例化的时候可以增加参数。

        以上就是该框架的目标,应该还不错吧。毕竟我们自己手写了框架代码,让我们会更加了解 IOC 的定义和实现。

二、手写框架

    1、我先把该框架的主要类型的代码贴出来,这个类型是核心类型,实现了我们上面定义的目标。

        首先、我们为 IOC 容器定义接口,面向接口编程嘛,可不要忘记了,所以,我们先顶一个接口,类型名称:ICustomContainer。        

 1     /// <summary>
 2     /// 我们定义的 IOC 容器抽象基类型,它定义了 IOC 容器的核心功能。
 3     /// </summary>
 4     public interface ICustomContainer
 5     {
 6         /// <summary>
 7         /// 提供服务的名称和参数构建实例以 TFrom 类型注册 TTo 实例。
 8         /// </summary>
 9         /// <typeparam name="TFrom">TTo 的基类类型。</typeparam>
10         /// <typeparam name="TTo">TFrom 的子类类型。</typeparam>
11         /// <param name="serviceName">要注册服务的名称。</param>
12         /// <param name="lifetime">要注册的服务的生命周期。</param>        
13         /// <param name="parameterValues">要注册的服务在构建实例时需要的非注入参数。</param>
14         void Register<TFrom, TTo>(string serviceName, ServiceLifetime lifetime, params object[] parameterValues) where TTo : TFrom;
15 
16         /// <summary>
17         /// 以指定名称解析该基类型的实例。
18         /// </summary>
19         /// <typeparam name="TFrom">要解析实例的基类型。</typeparam>
20         /// <param name="serviceName">要解析实例的名称。</param>
21         /// <returns></returns>
22         TFrom Resolve<TFrom>(string serviceName);
23     }

        再者,就是该接口的实现类型,该类型也是该容器的核心代码。代码不是很难,大家直接看吧。
        类型名称:PatrickContainer        

  1 using System;
  2 using System.Collections.Concurrent;
  3 using System.Collections.Generic;
  4 using System.Linq;
  5 using System.Reflection;
  6 using System.Threading;
  7 
  8 namespace PatrickLiu.NetCore50.IOCFramework.Container
  9 {
 10     /// <summary>
 11     /// 自定义的IOC容器实现。
 12     /// </summary>
 13     public sealed class PatrickContainer: ICustomContainer
 14     {
 15         private readonly IDictionary<string, ServiceMetadata> _Container;
 16         private readonly IDictionary<string, object[]> _Parameters;
 17         private readonly IDictionary<string, object> _ScopedContainer;
 18 
 19 
 20         /// <summary>
 21         /// 初始化类型的新实例,实例化容器。
 22         /// </summary>
 23         public PatrickContainer()
 24         {
 25             _Container = new ConcurrentDictionary<string, ServiceMetadata>();
 26             _Parameters = new ConcurrentDictionary<string, object[]>();
 27             _ScopedContainer = new Dictionary<string, object>();
 28         }
 29 
 30         /// <summary>
 31         /// 可以创建子作用域。
 32         /// </summary>
 33         /// <returns></returns>
 34         public PatrickContainer CreateScoped()
 35         {
 36             return new PatrickContainer(_Container, _Parameters, new Dictionary<string, object>());
 37         }
 38 
 39         /// <summary>
 40         /// 通过是有构造函数初始化容器。
 41         /// </summary>
 42         /// <param name="container"></param>
 43         /// <param name="parameters"></param>
 44         /// <param name="scopedContainer"></param>
 45         private PatrickContainer(IDictionary<string, ServiceMetadata> container, IDictionary<string, object[]> parameters, IDictionary<string, object> scopedContainer)
 46         {
 47             this._Container = container;
 48             this._Parameters = parameters;
 49             this._ScopedContainer = scopedContainer;
 50         }
 51 
 52         /// <summary>
 53         /// 以 TFrom 类型注册 TTo 实例。
 54         /// </summary>
 55         /// <typeparam name="TFrom">TTo 的基类类型</typeparam>
 56         /// <typeparam name="TTo">TFrom 的子类类型。</typeparam>
 57         public void Register<TFrom, TTo>() where TTo : TFrom
 58         {
 59             Register<TFrom, TTo>(null, ServiceLifetime.Transient, null);
 60         }
 61 
 62         /// <summary>
 63         /// 以 TFrom 类型注册 TTo 实例。
 64         /// </summary>
 65         /// <typeparam name="TFrom">TTo 的基类类型</typeparam>
 66         /// <typeparam name="TTo">TFrom 的子类类型。</typeparam>
 67         /// <param name="lifetime">要注册的服务的生命周期。</param>
 68         public void Register<TFrom, TTo>(ServiceLifetime lifetime) where TTo : TFrom
 69         {
 70             Register<TFrom, TTo>(null, lifetime, null);
 71         }
 72 
 73         /// <summary>
 74         /// 提供服务构建实例所需参数来以 TFrom 类型注册 TTo 实例。
 75         /// </summary>
 76         /// <typeparam name="TFrom">TTo 的基类类型</typeparam>
 77         /// <typeparam name="TTo">TFrom 的子类类型。</typeparam>
 78         /// <param name="parameterValues">要注册的服务在构建实例时需要的非注入参数。</param>
 79         public void Register<TFrom, TTo>(params object[] parameterValues) where TTo : TFrom
 80         {
 81             Register<TFrom, TTo>(null, ServiceLifetime.Transient, parameterValues);
 82         }
 83 
 84         /// <summary>
 85         /// 提供服务的名称构建实例来以 TFrom 类型注册 TTo 实例。
 86         /// </summary>
 87         /// <typeparam name="TFrom">TTo 的基类类型</typeparam>
 88         /// <typeparam name="TTo">TFrom 的子类类型。</typeparam>
 89         /// <param name="serviceName">要注册服务的名称。</param>
 90         public void Register<TFrom, TTo>(string serviceName) where TTo : TFrom
 91         {
 92             Register<TFrom, TTo>(serviceName, ServiceLifetime.Transient, null);
 93         }
 94 
 95         /// <summary>
 96         /// 提供服务的名称构建实例来以 TFrom 类型注册 TTo 实例。
 97         /// </summary>
 98         /// <typeparam name="TFrom">TTo 的基类类型</typeparam>
 99         /// <typeparam name="TTo">TFrom 的子类类型。</typeparam>
100         /// <param name="serviceName">要注册服务的名称。</param>
101         /// <param name="lifetime">要注册的服务的生命周期。</param>
102         public void Register<TFrom, TTo>(string serviceName, ServiceLifetime lifetime) where TTo : TFrom
103         {
104             Register<TFrom, TTo>(serviceName, lifetime, null);
105         }
106 
107         /// <summary>
108         /// 提供服务的名称和参数构建实例以 TFrom 类型注册 TTo 实例。
109         /// </summary>
110         /// <typeparam name="TFrom">TTo 的基类类型</typeparam>
111         /// <typeparam name="TTo">TFrom 的子类类型。</typeparam>
112         /// <param name="serviceName">要注册服务的名称。</param>
113         /// <param name="lifetime">要注册的服务的生命周期。</param>        
114         /// <param name="parameterValues">要注册的服务在构建实例时需要的非注入参数。</param>
115         public void Register<TFrom, TTo>(string serviceName, ServiceLifetime lifetime, params object[] parameterValues) where TTo : TFrom
116         {
117             string key;
118             if (string.IsNullOrEmpty(serviceName) || string.IsNullOrWhiteSpace(serviceName))
119             {
120                 key = typeof(TFrom).FullName;
121                 if (!_Container.ContainsKey(key))
122                 {
123                     _Container.Add(key, new ServiceMetadata() { ServiceType = typeof(TTo), Lifetime = lifetime });
124                 }
125             }
126             else
127             {
128                 key = string.Format("{0}_{1}", typeof(TFrom).FullName, serviceName);
129                 if (!_Container.ContainsKey(key))
130                 {
131                     _Container.Add(key, new ServiceMetadata() { ServiceType = typeof(TTo), Lifetime = lifetime });
132                 }
133             }
134             if (parameterValues != null && parameterValues.Length > 0)
135             {
136                 _Parameters.Add(key, parameterValues);
137             }
138         }
139 
140         /// <summary>
141         /// 以指定类型解析该类型的实例。
142         /// </summary>
143         /// <typeparam name="TFrom">要解析实例的基类型。</typeparam>
144         /// <returns></returns>
145         public TFrom Resolve<TFrom>()
146         {
147             return Resolve<TFrom>(null);
148         }
149 
150         /// <summary>
151         /// 以指定名称解析该基类型的实例。
152         /// </summary>
153         /// <typeparam name="TFrom">要解析实例的基类型。</typeparam>
154         /// <param name="serviceName">要解析实例的名称。</param>
155         /// <returns></returns>
156         public TFrom Resolve<TFrom>(string serviceName)
157         {
158             return (TFrom)Create(typeof(TFrom), serviceName);
159         }
160 
161 
162         /// <summary>
163         /// 通过递归实现解析实例对象。
164         /// </summary>
165         /// <param name="baseType">服务的基类型。</param>
166         /// <param name="serviceName">服务实例的名称。</param>
167         /// <returns></returns>
168         private object Create(Type baseType, string serviceName = null)
169         {
170             #region 处理关键字
171 
172             string keyword;
173 
174             if (string.IsNullOrEmpty(serviceName) || string.IsNullOrWhiteSpace(serviceName))
175             {
176                 keyword = string.Format("{0}", baseType.FullName);
177             }
178             else
179             {
180                 keyword = string.Format("{0}_{1}", baseType.FullName, serviceName);
181             }
182 
183             #endregion
184 
185             Type targetType = null; ServiceLifetime lifetime = ServiceLifetime.Transient;
186             if (_Container.ContainsKey(keyword))
187             {
188                 targetType = _Container[keyword].ServiceType;
189                 lifetime = _Container[keyword].Lifetime;
190             }
191             else if (keyword.IndexOf('_') != -1)
192             {
193                 if (_Container.ContainsKey(keyword.Split('_')[0]))
194                 {
195                     keyword = keyword.Split('_')[0];
196                     targetType = _Container[keyword].ServiceType;
197                     lifetime = _Container[keyword].Lifetime;
198                 }
199             }
200             else
201             {
202                 throw new Exception("类型还未注册!");
203             }
204 
205             #region 生命周期
206 
207             switch (lifetime)
208             {
209                 case ServiceLifetime.Transient:
210                     break;
211                 case ServiceLifetime.Singleton:
212                     if (_Container[keyword].SingletonInstance != null)
213                     {
214                         return _Container[keyword].SingletonInstance;
215                     }
216                     break;
217                 case ServiceLifetime.Scoped:
218                     if (_ScopedContainer.ContainsKey(keyword))
219                     {
220                         return _ScopedContainer[keyword];
221                     }
222                     break;
223                 case ServiceLifetime.PerThread:
224                     var objInstance = CallContext.GetData($"{keyword}{Thread.CurrentThread.ManagedThreadId}");
225                     if (objInstance != null)
226                     {
227                         return objInstance;
228                     }
229                     break;
230                 default:
231                     break;
232             }
233 
234             #endregion
235 
236             #region 选择构造函数
237 
238             ConstructorInfo ctor = null;
239 
240             //1、通过特性约束
241             ctor = targetType.GetConstructors().FirstOrDefault(c => c.IsDefined(typeof(SelectedConstructorAttribute), true));
242 
243             if (ctor == null)
244             {
245                 //2、参数最多的
246                 ctor = targetType.GetConstructors().OrderByDescending(c => c.GetParameters().Length).First();
247             }
248 
249             #endregion
250 
251             #region 核心创建对象代码
252 
253             IList<object> parameters = new List<object>();
254             var values = _Parameters.ContainsKey(keyword) ? _Parameters[keyword] : null;
255             int index = 0;
256             foreach (var parameter in ctor.GetParameters())
257             {
258                 if (values != null && values.Length > 0 && parameter.IsDefined(typeof(ConstantPatameterAttribute), true))
259                 {
260                     parameters.Add(values[index++]);
261                 }
262                 else
263                 {
264                     var parameterType = parameter.ParameterType;
265                     var instance = Create(parameterType, serviceName);
266                     parameters.Add(instance);
267                 }
268             }
269             object oIntance = Activator.CreateInstance(targetType, parameters.ToArray());
270 
271             #endregion
272 
273             #region 属性注入
274 
275             Type propertyType = null;
276             foreach (var property in targetType.GetProperties().Where(p => p.IsDefined(typeof(InjectionPropertyAttribute), true)))
277             {
278                 propertyType = property.PropertyType;
279                 var propInstance = Create(propertyType);
280                 property.SetValue(oIntance, propInstance);
281             }
282 
283             #endregion
284 
285             #region 方法注入
286 
287             foreach (var methodInfo in targetType.GetMethods().Where(p => p.IsDefined(typeof(InjectionMethodAttribute), true)))
288             {
289                 IList<object> methodParameters = new List<object>();
290                 values = _Parameters.ContainsKey(keyword) ? _Parameters[keyword] : null;
291                 index = 0;
292                 foreach (var parameter in methodInfo.GetParameters())
293                 {
294                     if (values != null && values.Length > 0 && parameter.IsDefined(typeof(ConstantPatameterAttribute)))
295                     {
296                         methodParameters.Add(values[index++]);
297                     }
298                     else
299                     {
300                         var methodParaType = parameter.ParameterType;
301                         var paraInstance = Create(methodParaType, serviceName);
302                         methodParameters.Add(paraInstance);
303                     }
304                 }
305                 methodInfo.Invoke(oIntance, methodParameters.ToArray());
306             }
307 
308             #endregion
309 
310             #region 生命周期
311 
312             switch (lifetime)
313             {
314                 case ServiceLifetime.Transient:
315                     break;
316                 case ServiceLifetime.Singleton:
317                     if (_Container[keyword].SingletonInstance == null)
318                     {
319                         _Container[keyword].SingletonInstance = oIntance;
320                     }
321                     break;
322                 case ServiceLifetime.Scoped:
323                     if (!_ScopedContainer.ContainsKey(keyword))
324                     {
325                         _ScopedContainer.Add(keyword, oIntance);
326                     }
327                     break;
328                 case ServiceLifetime.PerThread:
329                     CallContext.SetData($"{keyword}{Thread.CurrentThread.ManagedThreadId}", oIntance);
330                     break;
331                 default:
332                     break;
333             }
334 
335             #endregion
336 
337             return oIntance;
338         }
339     }
340 }

        当然了,还有一些其他的辅助类型,这么大的框架,还是要需要一些辅助类型的,接下来我们一一介绍。

    2、ConstantPatameterAttribute类型

        该类型是一个标记特性,用于标注不需要注入而进行传递的参数,可以使用该属性。

 1 using System;
 2 
 3 namespace PatrickLiu.NetCore50.IOCFramework.Container
 4 {
 5     /// <summary>
 6     /// 该类型定义了在服务初始化的时候需要从外界出入的参数,如果参数被标注,则说明改参数所需要的参数从外界传入。该类型是密封类型,不可以被继承。
 7     /// </summary>
 8     [AttributeUsage(AttributeTargets.Parameter|AttributeTargets.GenericParameter,AllowMultiple =false,Inherited =true)]
 9     public sealed class ConstantPatameterAttribute:Attribute
10     {
11     }
12 }

    3、InjectionMethodAttribute 类型

        该类型也是一个标记特性,用于标记方法,可以通过方法实现注入。

 1 using System;
 2 
 3 namespace PatrickLiu.NetCore50.IOCFramework.Container
 4 {
 5     /// <summary>
 6     /// 该类型定义了方法注入的特性类型,该类型是密封类型,不可以被继承。它也是一个标识类型。
 7     /// </summary>
 8     [AttributeUsage(AttributeTargets.Method,AllowMultiple =false,Inherited =true)]
 9     public sealed class InjectionMethodAttribute:Attribute
10     {
11     }
12 }

    4、InjectionPropertyAttribute 类型。

      该类型也是一个标记特性,用于标记正在属性上,可以通过属性实现注入。

 1 using System;
 2 
 3 namespace PatrickLiu.NetCore50.IOCFramework.Container
 4 {
 5     /// <summary>
 6     /// 该特性是一个实现属性注入的特性类,该类型是密封的。它是一个标识属性。
 7     /// </summary>
 8     [AttributeUsage(AttributeTargets.Property, AllowMultiple = false, Inherited = true)]
 9     public sealed class InjectionPropertyAttribute : Attribute
10     {
11     }
12 }

    5、SelectedConstructorAttribute 类型

      在我们构建类型实例的时候,可以通过该特性选择通过哪个构造函数创建实例。默认情况是选择参数最多的构造函数,也可以通过该特性选择构造函数。

 1 using System;
 2 
 3 namespace PatrickLiu.NetCore50.IOCFramework.Container
 4 {
 5     /// <summary>
 6     /// 选择构造函数。
 7     /// </summary>
 8     [AttributeUsage(AttributeTargets.Constructor, AllowMultiple = false, Inherited = true)]
 9     public sealed class SelectedConstructorAttribute : Attribute
10     {
11     }
12 }

    6、ServiceLifetime 枚举类型。

      我们可以实现对注册服务的生命周期的管理,类型简单,不多说了。

 1 namespace PatrickLiu.NetCore50.IOCFramework.Container
 2 {
 3     /// <summary>
 4     /// 服务的生命周期。
 5     /// </summary>
 6     public enum ServiceLifetime
 7     {
 8         /// <summary>
 9         /// 瞬时服务实例。
10         /// </summary>
11         Transient,
12 
13         /// <summary>
14         /// 单例服务实例。
15         /// </summary>
16         Singleton,
17 
18         /// <summary>
19         /// 作用域服务实例。
20         /// </summary>
21         Scoped,
22 
23         /// <summary>
24         /// 线程服务实例。
25         /// </summary>
26         PerThread
27     }
28 }

    7、ServiceMetadata 类型。

        用于定义注册服务的对象。

 1 using System;
 2 
 3 namespace PatrickLiu.NetCore50.IOCFramework.Container
 4 {
 5     /// <summary>
 6     /// 该类型定义了注册服务的元数据。
 7     /// </summary>
 8     public sealed class ServiceMetadata
 9     {
10         /// <summary>
11         /// 获取或者设置注册服务的类型。
12         /// </summary>
13         public Type ServiceType { get; set; }
14 
15         /// <summary>
16         /// 获取或者设置注册服务的生命周期。
17         /// </summary>
18         public ServiceLifetime Lifetime { get; set; }
19 
20         /// <summary>
21         /// 获取或者设置单件的服务实例。
22         /// </summary>
23         public Object SingletonInstance { get; set; }
24     }
25 }

      8、CallContext类型。

在NetCore 环境中,没有CallContext 类型,所以只能自己实现一个,可以实现基于线程来管理注册服务的生命周期。

 1 using System.Collections.Concurrent;
 2 using System.Threading;
 3 
 4 namespace PatrickLiu.NetCore50.IOCFramework.Container
 5 {
 6     /// <summary>
 7     /// Provides a way to set contextual data that flows with the call and async context of a test or invocation.
 8     /// </summary>
 9     public static class CallContext
10     {
11         private static ConcurrentDictionary<string, AsyncLocal<object>> state = new ConcurrentDictionary<string, AsyncLocal<object>>();
12 
13         /// <summary>
14         /// Stores a given object and associates it with the specified name.
15         /// </summary>
16         /// <param name="name">The name with which to associate the new item in the call context.</param>
17         /// <param name="data">The object to store in the call context.</param>
18         public static void SetData(string name, object data) =>
19             state.GetOrAdd(name, _ => new AsyncLocal<object>()).Value = data;
20 
21         /// <summary>
22         /// Retrieves an object with the specified name from the <see cref="CallContext"/>.
23         /// </summary>
24         /// <param name="name">The name of the item in the call context.</param>
25         /// <returns>The object in the call context associated with the specified name, or <see langword="null"/> if not found.</returns>
26         public static object GetData(string name) =>
27             state.TryGetValue(name, out AsyncLocal<object> data) ? data.Value : null;
28     }
29 
30     /// <summary>
31     /// 可以测试
32     /// </summary>
33     /// <typeparam name="T"></typeparam>
34     public static class CallContext<T>
35     {
36         static ConcurrentDictionary<string, AsyncLocal<T>> state = new ConcurrentDictionary<string, AsyncLocal<T>>();
37 
38         /// <summary>
39         /// Stores a given object and associates it with the specified name.
40         /// </summary>
41         /// <param name="name">The name with which to associate the new item in the call context.</param>
42         /// <param name="data">The object to store in the call context.</param>
43         public static void SetData(string name, T data) =>
44             state.GetOrAdd(name, _ => new AsyncLocal<T>()).Value = data;
45 
46         /// <summary>
47         /// Retrieves an object with the specified name from the <see cref="CallContext"/>.
48         /// </summary>
49         /// <typeparam name="T">The type of the data being retrieved. Must match the type used when the <paramref name="name"/> was set via <see cref="SetData{T}(string, T)"/>.</typeparam>
50         /// <param name="name">The name of the item in the call context.</param>
51         /// <returns>The object in the call context associated with the specified name, or a default value for <typeparamref name="T"/> if none is found.</returns>
52         public static T GetData(string name) =>
53             state.TryGetValue(name, out AsyncLocal<T> data) ? data.Value : default(T);
54     }
55 }

三、测试代码

    我们为了更好的测试我们写的IOC容器,我另外建立两个独立的类库项目和一个控制台应用程序。当然了,引用关系别忘记了。

    1、我们定义的接口类库,里面包含了测试用到的所有接口类型。很简单,不多说。

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

1     /// <summary>
2     /// ServiceA的服务接口
3     /// </summary>
4     public interface IServiceA
5     {
6         void Show();
7     }
1     public interface IServiceB
2     {
3         void Show();
4     }
1     public interface IServiceC
2     {
3         void Show();
4     }
1     public interface IServiceD
2     {
3         void Show();
4     }
1     public interface IServiceE
2     {
3         void Show();
4     }
1     public interface IServiceF
2     {
3         void Show();
4     }

    2、第一步我们定义了接口类库,这里我们定义实现了接口类库的服务类库,很简单,不多说。

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

 1     /// <summary>
 2     /// 自定义类型的服务。
 3     /// </summary>
 4     public class MyServiceA : IServiceA
 5     {
 6         public MyServiceA()
 7         {
 8             Console.WriteLine("MyServiceA is Created");
 9         }        
10 
11         /// <summary>
12         /// 方法执行
13         /// </summary>
14         public void Show()
15         {
16             Console.WriteLine("MyServiceA-show()");
17         }
18     }
 1     /// <summary>
 2     /// 自定义类型服务第二版本。
 3     /// </summary>
 4     public sealed class MyServiceA2 : IServiceA
 5     {
 6         private IServiceF _IServiceF;
 7 
 8         /// <summary>
 9         /// 构造函数
10         /// </summary>
11         public MyServiceA2()
12         {
13             Console.WriteLine("MyServiceA2 is created");
14         }
15 
16         /// <summary>
17         /// 方法注入。
18         /// </summary>
19         /// <param name="service"></param>
20         [InjectionMethod]
21         public void MethodInjection(IServiceF service)
22         {
23             _IServiceF = service;
24         }
25 
26         /// <summary>
27         /// 方法执行。
28         /// </summary>
29         public void Show()
30         {
31             Console.WriteLine("MyServiceA2--Show()");
32         }
33     }
 1     public class MyServiceA3 : IServiceA
 2     {
 3         /// <summary>
 4         /// 
 5         /// </summary>
 6         /// <param name="age"></param>
 7         /// <param name="name"></param>
 8         /// <param name="school"></param>        
 9         public MyServiceA3([ConstantPatameter]int age, [ConstantPatameter] string name, [ConstantPatameter] string school)
10         {
11             Console.WriteLine($"{age}{name}{school} MyServiceA3 is created");
12         }
13 
14 
15         public void Show()
16         {
17             Console.WriteLine("MyServiceA3-Show() is executed!");
18         }
19     }
 1     public class MyServiceA4 : IServiceA
 2     {
 3         private IServiceF _IServiceF;
 4 
 5         public MyServiceA4()
 6         {
 7             Console.WriteLine("");
 8         }
 9 
10         /// <summary>
11         /// 方法注入
12         /// </summary>
13         /// <param name="service">注入服务</param>
14         /// <param name="age"></param>
15         /// <param name="name"></param>
16         [InjectionMethod]
17         public void MethodInjection(IServiceF service,[ConstantPatameter]int age,[ConstantPatameter]string name)
18         {
19             _IServiceF = service;
20             Console.WriteLine($"{name} 今年 {age} 岁了。");
21         }
22 
23         public void Show()
24         {
25             Console.WriteLine("MyServiceA4--show() executing");
26         }
27     }
 1     /// <summary>
 2     /// 
 3     /// </summary>
 4     public class MyServiceB : IServiceB
 5     {
 6         /// <summary>
 7         /// 
 8         /// </summary>
 9         /// <param name="serviceC"></param>
10         /// <param name="serviceE"></param>
11         public MyServiceB(IServiceC serviceC,IServiceE serviceE)
12         {
13             Console.WriteLine("MyServiceB is created");
14         }
15 
16         /// <summary>
17         /// 
18         /// </summary>
19         public void Show()
20         {
21             Console.WriteLine("MyServiceB-Show()");
22         }
23     }
 1     /// <summary>
 2     /// 
 3     /// </summary>
 4     public class MyServiceC : IServiceC
 5     {
 6         /// <summary>
 7         /// 
 8         /// </summary>
 9         /// <param name="serviceD"></param>
10         public MyServiceC(IServiceD serviceD)
11         {
12             Console.WriteLine("MyServiceC is created");
13         }
14 
15         /// <summary>
16         /// 
17         /// </summary>
18         public void Show()
19         {
20             Console.WriteLine("MyServiceC-Show()");
21         }
22     }
 1     /// <summary>
 2     /// 自定义类型的服务。
 3     /// </summary>
 4     public class MyServiceD : IServiceD
 5     {
 6         /// <summary>
 7         /// 构造函数
 8         /// </summary>
 9         public MyServiceD()
10         {
11             Console.WriteLine("MyServiceD is created");
12         }
13 
14         /// <summary>
15         /// 方法执行。
16         /// </summary>
17         public void Show()
18         {
19             Console.WriteLine("MyServiceD--show()");
20         }
21     }
 1     /// <summary>
 2     /// 自定义服务类型。
 3     /// </summary>
 4     public class MyServiceE : IServiceE
 5     {
 6         /// <summary>
 7         /// 构造函数
 8         /// </summary>
 9         public MyServiceE()
10         {
11             Console.WriteLine("MyServiceE is created");
12         }
13 
14         /// <summary>
15         /// 属性注入
16         /// </summary>
17         [InjectionProperty]
18         public IServiceF ServiceF { get; set; }
19 
20         /// <summary>
21         /// 方法执行。
22         /// </summary>
23         public void Show()
24         {
25             Console.WriteLine("MyServiceE-Show()");
26         }
27     }
 1     /// <summary>
 2     /// 自定义类型服务。
 3     /// </summary>
 4     public sealed class MyServiceF : IServiceF
 5     {
 6         /// <summary>
 7         /// 构造函数
 8         /// </summary>
 9         public MyServiceF()
10         {
11             Console.WriteLine("MyServiceF is created!");
12         }
13 
14         /// <summary>
15         /// 方法执行。
16         /// </summary>
17         public void Show()
18         {
19             Console.WriteLine("MyServiceF--Show()");
20         }
21     }

    3、这个代码就是我们控制台项目,用来做测试的,很简单,不多说了。
      

  1 class Program
  2     {
  3         static void Main(string[] args)
  4         {
  5             //最简单版本
  6             {
  7                 PatrickContainer container = new PatrickContainer();
  8                 container.Register<IServiceA, MyServiceA>();
  9 
 10                 var instance = container.Resolve<IServiceA>();
 11                 instance.Show();
 12             }
 13             //可以多层依赖,可以包含属性注入
 14             {
 15                 PatrickContainer container = new PatrickContainer();
 16                 container.Register<IServiceA, MyServiceA>();
 17                 container.Register<IServiceB, MyServiceB>();
 18                 container.Register<IServiceC, MyServiceC>();
 19                 container.Register<IServiceD, MyServiceD>();
 20                 container.Register<IServiceE, MyServiceE>();
 21                 container.Register<IServiceF, MyServiceF>();
 22 
 23                 var instance = container.Resolve<IServiceB>();
 24                 instance.Show();
 25             }
 26             //单接口多实例,也包含方法注入
 27             {
 28                 PatrickContainer container = new PatrickContainer();
 29                 container.Register<IServiceA, MyServiceA>("A");
 30                 container.Register<IServiceA, MyServiceA2>("A2");
 31                 container.Register<IServiceF, MyServiceF>();
 32 
 33                 var instance = container.Resolve<IServiceA>("A");
 34                 instance.Show();
 35                 instance = container.Resolve<IServiceA>("A2");
 36                 instance.Show();
 37             }
 38             //构造函数参数、方法参数
 39             {
 40                 PatrickContainer container = new PatrickContainer();
 41                 
 42                 container.Register<IServiceA, MyServiceA3>(20,"zhangfei","涞源第一中学");
 43                 
 44                 var instance = container.Resolve<IServiceA>();
 45                 instance.Show();
 46             }
 47             {
 48                 PatrickContainer container = new PatrickContainer();
 49 
 50                 container.Register<IServiceA, MyServiceA4>(20, "张飞");
 51                 container.Register<IServiceF, MyServiceF>();
 52 
 53                 var instance = container.Resolve<IServiceA>();
 54                 instance.Show();
 55             }
 56             //声明周期
 57             {
 58                 //单例
 59                 PatrickContainer container = new PatrickContainer();
 60                 container.Register<IServiceA, MyServiceA>(ServiceLifetime.Singleton);
 61 
 62 
 63                 var instance = container.Resolve<IServiceA>();
 64                 var instance2 = container.Resolve<IServiceA>();
 65 
 66                 Console.WriteLine(Object.ReferenceEquals(instance,instance2));//True
 67             }
 68             //
 69             {
 70                 //瞬时
 71                 PatrickContainer container = new PatrickContainer();
 72                 container.Register<IServiceA, MyServiceA>(ServiceLifetime.Transient);
 73 
 74 
 75                 var instance = container.Resolve<IServiceA>();
 76                 var instance2 = container.Resolve<IServiceA>();
 77 
 78                 Console.WriteLine(Object.ReferenceEquals(instance, instance2));//False
 79             }
 80             {
 81                 //作用域
 82                 PatrickContainer container = new PatrickContainer();
 83                 container.Register<IServiceA, MyServiceA>(ServiceLifetime.Scoped);
 84 
 85 
 86                 var instance = container.Resolve<IServiceA>();
 87                 var instance2 = container.Resolve<IServiceA>();
 88 
 89                 Console.WriteLine(Object.ReferenceEquals(instance, instance2));//True
 90 
 91                 var container2 = container.CreateScoped();
 92                 var objedd=container2.Resolve<IServiceA>();
 93                 var objedd2=container2.Resolve<IServiceA>();
 94 
 95                 /Console.WriteLine(Object.ReferenceEquals(objedd, objedd2));//True
 96 
 97                 Console.WriteLine(Object.ReferenceEquals(instance, objedd2));//False
 98                 Console.ReadLine();
 99             }
100             {
101                 //线程
102                 PatrickContainer container = new PatrickContainer();
103                 container.Register<IServiceA, MyServiceA>(ServiceLifetime.PerThread);
104 
105                 IServiceA instance = null;
106                 IServiceA instance2 = null;
107                 IServiceA instance3 = null;
108                 IServiceA instance4 = null;
109                 IServiceA instance5 = null;
110                 IServiceA instance6 = null;
111 
112                 Task.Run(()=> {
113                     Console.WriteLine($"instance,当前线程的ID:{Thread.CurrentThread.ManagedThreadId}");
114                     instance = container.Resolve<IServiceA>();
115                 });
116 
117                 Task.Run(() => {
118                     Console.WriteLine($"instance2,当前线程的ID:{Thread.CurrentThread.ManagedThreadId}");
119                     instance2 = container.Resolve<IServiceA>();
120                 });
121 
122                 Task.Run(() => {
123                     Console.WriteLine($"instance3 和 instance4,当前线程的ID:{Thread.CurrentThread.ManagedThreadId}");
124                     instance3 = container.Resolve<IServiceA>();
125                     instance4 = container.Resolve<IServiceA>();
126                 });
127 
128                 Task.Run(() => {
129                     Console.WriteLine($"instance5,当前线程的ID:{Thread.CurrentThread.ManagedThreadId}");
130                     instance5 = container.Resolve<IServiceA>();
131                 }).ContinueWith(t=> {
132                     Console.WriteLine($"instance6,当前线程的ID:{Thread.CurrentThread.ManagedThreadId}");
133                     instance6 = container.Resolve<IServiceA>();
134                 });
135 
136                 Thread.Sleep(1000);
137 
138                 Console.WriteLine(Object.ReferenceEquals(instance, instance2));//False
139                 Console.WriteLine(Object.ReferenceEquals(instance, instance3));//False
140                 Console.WriteLine(Object.ReferenceEquals(instance, instance4));//False
141                 Console.WriteLine(Object.ReferenceEquals(instance2, instance3));//False
142                 Console.WriteLine(Object.ReferenceEquals(instance2, instance4));//False
143                 Console.WriteLine(Object.ReferenceEquals(instance3, instance4));//True
144 
145                 Console.WriteLine(Object.ReferenceEquals(instance5, instance6));//False                
146             }
147             
148             Console.Read();
149         }
150     }

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


About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK