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


    一、介绍

        1、介绍

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

        2、开发环境

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

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

            3)、开发语言:C#

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

        3、实现目标

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

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

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

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

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

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

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

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

    二、手写框架

        

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

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

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

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

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

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

        2、ConstantPatameterAttribute类型

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

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

        3、InjectionMethodAttribute 类型

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

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

        4、InjectionPropertyAttribute 类型。

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

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

        5、SelectedConstructorAttribute 类型

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

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

        6、ServiceLifetime 枚举类型。

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

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

        7、ServiceMetadata 类型。

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

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


          8、CallContext类型。

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

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

    三、测试代码

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

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

            

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

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

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

            

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

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

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

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

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

    天下国家,可均也;爵禄,可辞也;白刃,可蹈也;中庸不可能也
  • 相关阅读:
    数据结构 【实验 串的基本操作】
    Ioc容器依赖注入-Spring 源码系列(2)
    定时任务管理中心(dubbo+spring)-我们到底能走多远系列47
    jvm内存增长问题排查简例
    Ioc容器beanDefinition-Spring 源码系列(1)
    SPI机制
    java工厂-积木系列
    java单例-积木系列
    利用spring AOP 和注解实现方法中查cache-我们到底能走多远系列(46)
    java 静态代理-积木系列
  • 原文地址:https://www.cnblogs.com/PatrickLiu/p/14998785.html
Copyright © 2020-2023  润新知