一、说明

所谓依赖注入,是指程序运行过程中,如果需要调用另一个对象协助时,无须在代码中创建被调用者,而是依赖于外部的注入。通俗来讲,就是把有依赖关系的类放到容器中,然后在我们需要这些类时,容器自动解析出这些类的实例。依赖注入最大的好处时实现类的解耦,利于程序拓展、单元测试、自动化模拟测试等。依赖注入的英文为:Dependency Injection,简称 DI。(说明来自网络)

RRQM内置了Container容器。只需要引入RRQMCore即可使用。

二、特点

  • 支持构造函数、属性、方法三种注入方式,可以选择其中部分生效。
  • 支持 Singleton、Scoped、Transient三种生命周期。
  • 支持单接口,多实现注入。
  • 支持当获取类型是可实例类型时,即使不注册,也能成功构造。
  • 支持默认参数注入。
  • 支持构建参数注入。
  • 支持标签参数注入。
  • 支持泛型注入。
  • 支持Object注入。

三、注入方式

对于一个类,默认情况下,会支持构造函数、属性、方法三种注入方式。但是,当明确知道该类型仅会使用其中部分方式注入时,可以设置注入类型,以此节约性能。
image.png

3.1 构造函数注入

其中MyLog1,MyLog2虽然没有注册,但是因为是实例,所以依然可以成功构造。

  1. [Fact]
  2. public void CtorShouldBeOk()
  3. {
  4. Container container = new Container();
  5. container.RegisterTransient<ILog, MyLog3>();
  6. var log3 = container.Resolve<ILog>() as MyLog3;
  7. Assert.NotNull(log3.MyLog1);
  8. Assert.NotNull(log3.MyLog2);
  9. }
  1. public class MyLog3 : ILog
  2. {
  3. public MyLog3(MyLog1 myLog1, MyLog2 myLog2)
  4. {
  5. this.MyLog1 = myLog1;
  6. this.MyLog2 = myLog2;
  7. }
  8. public MyLog1 MyLog1 { get; }
  9. public MyLog2 MyLog2 { get; }
  10. public void Debug(LogType logType, object source, string message, Exception exception)
  11. {
  12. }
  13. public void Debug(LogType logType, object source, string message)
  14. {
  15. }
  16. }

3.2 属性注入

使用DependencyParamterInject,或者DependencyInject标记属性,即可注入。

示例中使用的是单接口多实现,所以使用DependencyParamterInject标记。

  1. [Fact]
  2. public void PropertyShouldBeOk()
  3. {
  4. Container container = new Container();
  5. container.RegisterTransient<ILog, MyLog1>("MyLog1");
  6. container.RegisterTransient<ILog, MyLog2>("MyLog2");
  7. container.RegisterTransient<ILog, MyLog3>("MyLog3");
  8. container.RegisterTransient<ILog, MyLog5>();
  9. var log5 = container.Resolve<ILog>() as MyLog5;
  10. Assert.NotNull(log5.MyLog1);
  11. Assert.NotNull(log5.MyLog2);
  12. Assert.True(log5.MyLog1.GetType() == typeof(MyLog1));
  13. Assert.True(log5.MyLog2.GetType() == typeof(MyLog2));
  14. }
  1. public class MyLog5 : ILog
  2. {
  3. [DependencyParamterInject("MyLog1")]
  4. public ILog MyLog1 { get; set; }
  5. [DependencyParamterInject("MyLog2")]
  6. public ILog MyLog2 { get; set; }
  7. public void Debug(LogType logType, object source, string message, Exception exception)
  8. {
  9. }
  10. public void Debug(LogType logType, object source, string message)
  11. {
  12. }
  13. }

3.2 方法注入

使用DependencyInject标记属性,即可对方法注入。

同时,示例中演示了默认参数设定。在初始化MyLog6后,A=10,B=”RRQM”。

同时,还能嵌套MyLog1和MyLog4的同一接口的不同实现,和实现的默认参数构造。

  1. [Fact]
  2. public void MethodShouldBeOk()
  3. {
  4. Container container = new Container();
  5. container.RegisterTransient<ILog, MyLog1>("MyLog1");
  6. container.RegisterTransient<ILog, MyLog2>("MyLog2");
  7. container.RegisterTransient<ILog, MyLog3>("MyLog3");
  8. container.RegisterTransient<ILog, MyLog4>("MyLog4");
  9. container.RegisterTransient<ILog, MyLog6>("MyLog5");
  10. container.RegisterTransient<ILog, MyLog6>();
  11. var log6 = container.Resolve<ILog>() as MyLog6;
  12. Assert.NotNull(log6.MyLog1);
  13. Assert.NotNull(log6.MyLog4);
  14. Assert.True(log6.MyLog1.GetType() == typeof(MyLog1));
  15. Assert.True(log6.MyLog4.GetType() == typeof(MyLog4));
  16. Assert.True(((MyLog4)log6.MyLog4).A == 20);
  17. Assert.True(((MyLog4)log6.MyLog4).B == "IOU");
  18. }
  1. public class MyLog6 : ILog
  2. {
  3. [DependencyInject(10, "RRQM")]
  4. public void DependencyMethod(int a, string b, [DependencyParamterInject("MyLog1")] ILog myLog1, [DependencyParamterInject("MyLog4", 20, "IOU")] ILog myLog4)
  5. {
  6. this.A = a;
  7. this.B = b;
  8. this.MyLog1 = myLog1;
  9. this.MyLog4 = myLog4;
  10. }
  11. public int A { get; set; }
  12. public string B { get; set; }
  13. public ILog MyLog1 { get; set; }
  14. public ILog MyLog4 { get; set; }
  15. public void Debug(LogType logType, object source, string message, Exception exception)
  16. {
  17. }
  18. public void Debug(LogType logType, object source, string message)
  19. {
  20. }
  21. }

Object注入

  1. [Fact]
  2. public void ObjectSingletonShouldBeOk()
  3. {
  4. Container container = new Container();
  5. container.RegisterSingleton<ILog, MyLog1>();
  6. container.RegisterSingleton<ILog, MyLog10>("10");
  7. var log10 = container.Resolve<ILog>("10") as MyLog10;
  8. Assert.NotNull(log10);
  9. Assert.NotNull(log10.MyLog1);
  10. Assert.True(log10.MyLog1.GetType() == typeof(MyLog1));
  11. }
  1. public class MyLog10 : ILog
  2. {
  3. [DependencyParamterInject(typeof(ILog))]
  4. public object MyLog1 { get; set; }
  5. public void Debug(LogType logType, object source, string message, Exception exception)
  6. {
  7. }
  8. public void Debug(LogType logType, object source, string message)
  9. {
  10. }
  11. }

四、生命周期

生命周期是对注入构造的实例的有效性而言的。RRQM支持三种生命周期。

  • Singleton:单例注入,当注入,并且实例化以后,全局唯一实例。
  • Transient:瞬时注入,每次获取的实例都是新实例。
  • Scoped:区域单例注入,当在一个IScopedContainer时,实例唯一。

对于前两种,熟悉IOC的同学,相信都知道到。那接下来就演示一下Scoped。

实际上使用Scoped时,得先明确区域,也就是创建一个IScopedContainer的区域容器(类似Aps.net的IServiceProvider)。然后后续实例从IScopedContainer获得即可。

  1. [Fact]
  2. public void ScopedShouldBeOk()
  3. {
  4. Container container = new Container();
  5. container.RegisterScoped<ILog, MyLog1>();
  6. var log1 = container.Resolve<ILog>();
  7. var log2 = container.Resolve<ILog>();
  8. Assert.NotNull(log1);
  9. Assert.False(log1 == log2);
  10. IScopedContainer scopedContainer = container.Resolve<IScopedContainer>();
  11. log1 = scopedContainer.Resolve<ILog>();
  12. log2 = scopedContainer.Resolve<ILog>();
  13. Assert.NotNull(log1);
  14. Assert.True(log1 == log2);
  15. }

所有模型定义

  1. public interface IGeneric<T1, T2>
  2. {
  3. }
  4. public class Generic<T1, T2> : IGeneric<T1, T2>
  5. {
  6. }
  7. public class MyLog1 : ILog
  8. {
  9. public void Debug(LogType logType, object source, string message, Exception exception)
  10. {
  11. }
  12. public void Debug(LogType logType, object source, string message)
  13. {
  14. }
  15. }
  16. public class MyLog2 : ILog
  17. {
  18. public void Debug(LogType logType, object source, string message, Exception exception)
  19. {
  20. }
  21. public void Debug(LogType logType, object source, string message)
  22. {
  23. }
  24. }
  25. public class MyLog3 : ILog
  26. {
  27. public MyLog3(MyLog1 myLog1, MyLog2 myLog2)
  28. {
  29. this.MyLog1 = myLog1;
  30. this.MyLog2 = myLog2;
  31. }
  32. public MyLog1 MyLog1 { get; }
  33. public MyLog2 MyLog2 { get; }
  34. public void Debug(LogType logType, object source, string message, Exception exception)
  35. {
  36. }
  37. public void Debug(LogType logType, object source, string message)
  38. {
  39. }
  40. }
  41. public class MyLog4 : ILog
  42. {
  43. [DependencyInject(10, "RRQM")]
  44. public MyLog4(int a, string b, MyLog1 myLog1, MyLog2 myLog2)
  45. {
  46. this.A = a;
  47. this.B = b;
  48. this.MyLog1 = myLog1;
  49. this.MyLog2 = myLog2;
  50. }
  51. public int A { get; }
  52. public string B { get; }
  53. public MyLog1 MyLog1 { get; }
  54. public MyLog2 MyLog2 { get; }
  55. public void Debug(LogType logType, object source, string message, Exception exception)
  56. {
  57. }
  58. public void Debug(LogType logType, object source, string message)
  59. {
  60. }
  61. }
  62. public class MyLog5 : ILog
  63. {
  64. [DependencyParamterInject("MyLog1")]
  65. public ILog MyLog1 { get; set; }
  66. [DependencyParamterInject("MyLog2")]
  67. public ILog MyLog2 { get; set; }
  68. public void Debug(LogType logType, object source, string message, Exception exception)
  69. {
  70. }
  71. public void Debug(LogType logType, object source, string message)
  72. {
  73. }
  74. }
  75. public class MyLog6 : ILog
  76. {
  77. [DependencyInject(10, "RRQM")]
  78. public void DependencyMethod(int a, string b, [DependencyParamterInject("MyLog1")] ILog myLog1, [DependencyParamterInject("MyLog4", 20, "IOU")] ILog myLog4)
  79. {
  80. this.A = a;
  81. this.B = b;
  82. this.MyLog1 = myLog1;
  83. this.MyLog4 = myLog4;
  84. }
  85. public int A { get; set; }
  86. public string B { get; set; }
  87. public ILog MyLog1 { get; set; }
  88. public ILog MyLog4 { get; set; }
  89. public void Debug(LogType logType, object source, string message, Exception exception)
  90. {
  91. }
  92. public void Debug(LogType logType, object source, string message)
  93. {
  94. }
  95. }
  96. public class MyLog7 : ILog
  97. {
  98. public MyLog7(IGeneric<ILog, MyLog2> generic)
  99. {
  100. this.Generic = generic;
  101. }
  102. public IGeneric<ILog, MyLog2> Generic { get; }
  103. public void Debug(LogType logType, object source, string message, Exception exception)
  104. {
  105. }
  106. public void Debug(LogType logType, object source, string message)
  107. {
  108. }
  109. }
  110. [DependencyType(DependencyType.Constructor)]
  111. public class MyLog8 : ILog
  112. {
  113. [DependencyInject(10, "RRQM")]
  114. public void DependencyMethod(int a, string b, [DependencyParamterInject("MyLog1")] ILog myLog1, [DependencyParamterInject("MyLog4", 20, "IOU")] ILog myLog4)
  115. {
  116. this.A = a;
  117. this.B = b;
  118. this.MyLog1 = myLog1;
  119. this.MyLog4 = myLog4;
  120. }
  121. public int A { get; set; }
  122. public string B { get; set; }
  123. public ILog MyLog1 { get; set; }
  124. public ILog MyLog4 { get; set; }
  125. public void Debug(LogType logType, object source, string message, Exception exception)
  126. {
  127. }
  128. public void Debug(LogType logType, object source, string message)
  129. {
  130. }
  131. }
  132. [DependencyType(DependencyType.Constructor | DependencyType.Method)]
  133. public class MyLog9 : ILog
  134. {
  135. [DependencyInject(10, "RRQM")]
  136. public void DependencyMethod(int a, string b, [DependencyParamterInject("MyLog1")] ILog myLog1, [DependencyParamterInject("MyLog4", 20, "IOU")] ILog myLog4)
  137. {
  138. this.A = a;
  139. this.B = b;
  140. this.MyLog1 = myLog1;
  141. this.MyLog4 = myLog4;
  142. }
  143. public int A { get; set; }
  144. public string B { get; set; }
  145. public ILog MyLog1 { get; set; }
  146. public ILog MyLog4 { get; set; }
  147. public void Debug(LogType logType, object source, string message, Exception exception)
  148. {
  149. }
  150. public void Debug(LogType logType, object source, string message)
  151. {
  152. }
  153. }