一、说明
所谓依赖注入,是指程序运行过程中,如果需要调用另一个对象协助时,无须在代码中创建被调用者,而是依赖于外部的注入。通俗来讲,就是把有依赖关系的类放到容器中,然后在我们需要这些类时,容器自动解析出这些类的实例。依赖注入最大的好处时实现类的解耦,利于程序拓展、单元测试、自动化模拟测试等。依赖注入的英文为:Dependency Injection,简称 DI。(说明来自网络)
RRQM内置了Container容器。只需要引入RRQMCore即可使用。
二、特点
- 支持构造函数、属性、方法三种注入方式,可以选择其中部分生效。
 - 支持 Singleton、Scoped、Transient三种生命周期。
 - 支持单接口,多实现注入。
 - 支持当获取类型是可实例类型时,即使不注册,也能成功构造。
 - 支持默认参数注入。
 - 支持构建参数注入。
 - 支持标签参数注入。
 - 支持泛型注入。
 - 支持Object注入。
 
三、注入方式
对于一个类,默认情况下,会支持构造函数、属性、方法三种注入方式。但是,当明确知道该类型仅会使用其中部分方式注入时,可以设置注入类型,以此节约性能。
3.1 构造函数注入
其中MyLog1,MyLog2虽然没有注册,但是因为是实例,所以依然可以成功构造。
[Fact]public void CtorShouldBeOk(){Container container = new Container();container.RegisterTransient<ILog, MyLog3>();var log3 = container.Resolve<ILog>() as MyLog3;Assert.NotNull(log3.MyLog1);Assert.NotNull(log3.MyLog2);}
public class MyLog3 : ILog{public MyLog3(MyLog1 myLog1, MyLog2 myLog2){this.MyLog1 = myLog1;this.MyLog2 = myLog2;}public MyLog1 MyLog1 { get; }public MyLog2 MyLog2 { get; }public void Debug(LogType logType, object source, string message, Exception exception){}public void Debug(LogType logType, object source, string message){}}
3.2 属性注入
使用DependencyParamterInject,或者DependencyInject标记属性,即可注入。
示例中使用的是单接口多实现,所以使用DependencyParamterInject标记。
[Fact]public void PropertyShouldBeOk(){Container container = new Container();container.RegisterTransient<ILog, MyLog1>("MyLog1");container.RegisterTransient<ILog, MyLog2>("MyLog2");container.RegisterTransient<ILog, MyLog3>("MyLog3");container.RegisterTransient<ILog, MyLog5>();var log5 = container.Resolve<ILog>() as MyLog5;Assert.NotNull(log5.MyLog1);Assert.NotNull(log5.MyLog2);Assert.True(log5.MyLog1.GetType() == typeof(MyLog1));Assert.True(log5.MyLog2.GetType() == typeof(MyLog2));}
public class MyLog5 : ILog{[DependencyParamterInject("MyLog1")]public ILog MyLog1 { get; set; }[DependencyParamterInject("MyLog2")]public ILog MyLog2 { get; set; }public void Debug(LogType logType, object source, string message, Exception exception){}public void Debug(LogType logType, object source, string message){}}
3.2 方法注入
使用DependencyInject标记属性,即可对方法注入。
同时,示例中演示了默认参数设定。在初始化MyLog6后,A=10,B=”RRQM”。
同时,还能嵌套MyLog1和MyLog4的同一接口的不同实现,和实现的默认参数构造。
[Fact]public void MethodShouldBeOk(){Container container = new Container();container.RegisterTransient<ILog, MyLog1>("MyLog1");container.RegisterTransient<ILog, MyLog2>("MyLog2");container.RegisterTransient<ILog, MyLog3>("MyLog3");container.RegisterTransient<ILog, MyLog4>("MyLog4");container.RegisterTransient<ILog, MyLog6>("MyLog5");container.RegisterTransient<ILog, MyLog6>();var log6 = container.Resolve<ILog>() as MyLog6;Assert.NotNull(log6.MyLog1);Assert.NotNull(log6.MyLog4);Assert.True(log6.MyLog1.GetType() == typeof(MyLog1));Assert.True(log6.MyLog4.GetType() == typeof(MyLog4));Assert.True(((MyLog4)log6.MyLog4).A == 20);Assert.True(((MyLog4)log6.MyLog4).B == "IOU");}
public class MyLog6 : ILog{[DependencyInject(10, "RRQM")]public void DependencyMethod(int a, string b, [DependencyParamterInject("MyLog1")] ILog myLog1, [DependencyParamterInject("MyLog4", 20, "IOU")] ILog myLog4){this.A = a;this.B = b;this.MyLog1 = myLog1;this.MyLog4 = myLog4;}public int A { get; set; }public string B { get; set; }public ILog MyLog1 { get; set; }public ILog MyLog4 { get; set; }public void Debug(LogType logType, object source, string message, Exception exception){}public void Debug(LogType logType, object source, string message){}}
Object注入
[Fact]public void ObjectSingletonShouldBeOk(){Container container = new Container();container.RegisterSingleton<ILog, MyLog1>();container.RegisterSingleton<ILog, MyLog10>("10");var log10 = container.Resolve<ILog>("10") as MyLog10;Assert.NotNull(log10);Assert.NotNull(log10.MyLog1);Assert.True(log10.MyLog1.GetType() == typeof(MyLog1));}
public class MyLog10 : ILog{[DependencyParamterInject(typeof(ILog))]public object MyLog1 { get; set; }public void Debug(LogType logType, object source, string message, Exception exception){}public void Debug(LogType logType, object source, string message){}}
四、生命周期
生命周期是对注入构造的实例的有效性而言的。RRQM支持三种生命周期。
- Singleton:单例注入,当注入,并且实例化以后,全局唯一实例。
 - Transient:瞬时注入,每次获取的实例都是新实例。
 - Scoped:区域单例注入,当在一个IScopedContainer时,实例唯一。
 
对于前两种,熟悉IOC的同学,相信都知道到。那接下来就演示一下Scoped。
实际上使用Scoped时,得先明确区域,也就是创建一个IScopedContainer的区域容器(类似Aps.net的IServiceProvider)。然后后续实例从IScopedContainer获得即可。
[Fact]public void ScopedShouldBeOk(){Container container = new Container();container.RegisterScoped<ILog, MyLog1>();var log1 = container.Resolve<ILog>();var log2 = container.Resolve<ILog>();Assert.NotNull(log1);Assert.False(log1 == log2);IScopedContainer scopedContainer = container.Resolve<IScopedContainer>();log1 = scopedContainer.Resolve<ILog>();log2 = scopedContainer.Resolve<ILog>();Assert.NotNull(log1);Assert.True(log1 == log2);}
所有模型定义
public interface IGeneric<T1, T2>{}public class Generic<T1, T2> : IGeneric<T1, T2>{}public class MyLog1 : ILog{public void Debug(LogType logType, object source, string message, Exception exception){}public void Debug(LogType logType, object source, string message){}}public class MyLog2 : ILog{public void Debug(LogType logType, object source, string message, Exception exception){}public void Debug(LogType logType, object source, string message){}}public class MyLog3 : ILog{public MyLog3(MyLog1 myLog1, MyLog2 myLog2){this.MyLog1 = myLog1;this.MyLog2 = myLog2;}public MyLog1 MyLog1 { get; }public MyLog2 MyLog2 { get; }public void Debug(LogType logType, object source, string message, Exception exception){}public void Debug(LogType logType, object source, string message){}}public class MyLog4 : ILog{[DependencyInject(10, "RRQM")]public MyLog4(int a, string b, MyLog1 myLog1, MyLog2 myLog2){this.A = a;this.B = b;this.MyLog1 = myLog1;this.MyLog2 = myLog2;}public int A { get; }public string B { get; }public MyLog1 MyLog1 { get; }public MyLog2 MyLog2 { get; }public void Debug(LogType logType, object source, string message, Exception exception){}public void Debug(LogType logType, object source, string message){}}public class MyLog5 : ILog{[DependencyParamterInject("MyLog1")]public ILog MyLog1 { get; set; }[DependencyParamterInject("MyLog2")]public ILog MyLog2 { get; set; }public void Debug(LogType logType, object source, string message, Exception exception){}public void Debug(LogType logType, object source, string message){}}public class MyLog6 : ILog{[DependencyInject(10, "RRQM")]public void DependencyMethod(int a, string b, [DependencyParamterInject("MyLog1")] ILog myLog1, [DependencyParamterInject("MyLog4", 20, "IOU")] ILog myLog4){this.A = a;this.B = b;this.MyLog1 = myLog1;this.MyLog4 = myLog4;}public int A { get; set; }public string B { get; set; }public ILog MyLog1 { get; set; }public ILog MyLog4 { get; set; }public void Debug(LogType logType, object source, string message, Exception exception){}public void Debug(LogType logType, object source, string message){}}public class MyLog7 : ILog{public MyLog7(IGeneric<ILog, MyLog2> generic){this.Generic = generic;}public IGeneric<ILog, MyLog2> Generic { get; }public void Debug(LogType logType, object source, string message, Exception exception){}public void Debug(LogType logType, object source, string message){}}[DependencyType(DependencyType.Constructor)]public class MyLog8 : ILog{[DependencyInject(10, "RRQM")]public void DependencyMethod(int a, string b, [DependencyParamterInject("MyLog1")] ILog myLog1, [DependencyParamterInject("MyLog4", 20, "IOU")] ILog myLog4){this.A = a;this.B = b;this.MyLog1 = myLog1;this.MyLog4 = myLog4;}public int A { get; set; }public string B { get; set; }public ILog MyLog1 { get; set; }public ILog MyLog4 { get; set; }public void Debug(LogType logType, object source, string message, Exception exception){}public void Debug(LogType logType, object source, string message){}}[DependencyType(DependencyType.Constructor | DependencyType.Method)]public class MyLog9 : ILog{[DependencyInject(10, "RRQM")]public void DependencyMethod(int a, string b, [DependencyParamterInject("MyLog1")] ILog myLog1, [DependencyParamterInject("MyLog4", 20, "IOU")] ILog myLog4){this.A = a;this.B = b;this.MyLog1 = myLog1;this.MyLog4 = myLog4;}public int A { get; set; }public string B { get; set; }public ILog MyLog1 { get; set; }public ILog MyLog4 { get; set; }public void Debug(LogType logType, object source, string message, Exception exception){}public void Debug(LogType logType, object source, string message){}}
