关于.NET中的控制反转(三)- 依赖注入之最强 Autofac
一、Autofac简介
Autofac和其他容器的不同之处是它和C#语言的结合非常紧密,在使用过程中对你的应用的侵入性几乎为零,更容易与第三方的组件集成。Autofac的主要特性如下:
- 组件侵入性为零:组件不需要去引用Autofac。
- 灵活的模块化系统:通过模块化组织你的程序,应用程序不用纠缠于复 杂的XML配置系统或者是配置参数。
- 自动装配:可以是用lambda表达式注册你的组件,autofac会根据需要选择构造函数或者属 性注入
- XML配置文件的支持:XML配置文件过度使用时很丑陋,但是在发布的时候通常非常有用
- 组件的多服务支持:许 多设计师喜欢使用细粒度的接口来控制依赖 , autofac允许一个组件提供多个服务
二、Autofac安装
1:使用Nuget下载 “Autofac”库,需注意,使用 .net framework必须在4.7以上版本,低于4.7版本的安装会失败。
三、Autofac的注册 —— 使用类型进行注册与使用
1 using Autofac;
2 using System;
3
4 namespace BankOperation
5 {
6 class Program
7 {
8 static void Main(string[] args)
9 {
10 // 创建 ContainerBuilder
11 ContainerBuilder builder = new ContainerBuilder();
12
13 // 注册
14 builder.RegisterType<ABank>().As<IUnionPay>();
15
16 // 实例化
17 IContainer container = builder.Build();
18 var dev = container.Resolve<IUnionPay>();
19 dev.SaveMoneny(80);
20 dev.WithdrawMoney(50);
21
22 Console.ReadKey();
23 }
24
25 }
26
27 public interface IUnionPay
28 {
29 /// <summary>
30 /// 存钱
31 /// </summary>
32 /// <param name="amount">存钱金额</param>
33 void SaveMoneny(int amount);
34
35 /// <summary>
36 /// 取钱
37 /// </summary>
38 /// <param name="amount">取钱金额</param>
39 void WithdrawMoney(int amount);
40 }
41
42 public class ABank:IUnionPay
43 {
44 public void SaveMoneny(int amount)
45 {
46 Console.WriteLine($"把钱存入A银行,金额为:{amount}");
47 }
48
49 public void WithdrawMoney(int amount)
50 {
51 Console.WriteLine($"从A银行取钱,金额为:{amount}");
52 }
53 }
54 }
四、Autofac的注册 —— 使用别名进行注册与使用(一个接口有多个实现类时)
1 using Autofac;
2 using System;
3
4 namespace BankOperation
5 {
6 class Program
7 {
8 static void Main(string[] args)
9 {
10 Console.Write("请输入银行名称:");
11 string name = Console.ReadLine();
12 Operation(name);
13
14 Console.ReadKey();
15 }
16
17 static void Operation(string name)
18 {
19 // 创建 ContainerBuilder
20 ContainerBuilder builder = new ContainerBuilder();
21
22 // 使用别名进行注册
23 builder.RegisterType<ABank>().Named<IUnionPay>("A");
24 builder.RegisterType<BBank>().Named<IUnionPay>("B");
25
26 // 使用别名进行实例化
27 IContainer container = builder.Build();
28 var dev = container.ResolveNamed<IUnionPay>(name);
29 dev.SaveMoneny(80);
30 dev.WithdrawMoney(50);
31 }
32 }
33
34 public interface IUnionPay
35 {
36 /// <summary>
37 /// 存钱
38 /// </summary>
39 /// <param name="amount">存钱金额</param>
40 void SaveMoneny(int amount);
41
42 /// <summary>
43 /// 取钱
44 /// </summary>
45 /// <param name="amount">取钱金额</param>
46 void WithdrawMoney(int amount);
47 }
48
49 public class ABank:IUnionPay
50 {
51 public void SaveMoneny(int amount)
52 {
53 Console.WriteLine($"把钱存入A银行,金额为:{amount}");
54 }
55
56 public void WithdrawMoney(int amount)
57 {
58 Console.WriteLine($"从A银行取钱,金额为:{amount}");
59 }
60 }
61
62 public class BBank : IUnionPay
63 {
64 public void SaveMoneny(int amount)
65 {
66 Console.WriteLine($"把钱存入B银行,金额为:{amount}");
67 }
68
69 public void WithdrawMoney(int amount)
70 {
71 Console.WriteLine($"从B银行取钱,金额为:{amount}");
72 }
73 }
74 }
五、Autofac的注册 —— 使用Lambda进行注册与使用(传递参数时)
反射在组件创建时是个很好的选择. 但是, 当组件创建不再是简单的调用构造方法时, 事情将变得混乱起来。可通过Lambda表达式传递一个实例,通过实例的初始化函数和公共属性传递需要注入的信息:
1 using Autofac;
2 using System;
3
4 namespace BankOperation
5 {
6 class Program
7 {
8 static void Main(string[] args)
9 {
10 // 创建 ContainerBuilder
11 ContainerBuilder builder = new ContainerBuilder();
12
13 // 注册(通过实例化函数传递参数+类的公共属性)
14 builder.Register<IUnionPay>(c => new ABank("测试A银行"){ BankRate =8.12});
15
16 // 实例化
17 IContainer container = builder.Build();
18 var dev = container.Resolve<IUnionPay>();
19 dev.SaveMoneny(80);
20 dev.WithdrawMoney(50);
21
22 Console.ReadKey();
23 }
24
25 }
26
27 public interface IUnionPay
28 {
29 /// <summary>
30 /// 存钱
31 /// </summary>
32 /// <param name="amount">存钱金额</param>
33 void SaveMoneny(int amount);
34
35 /// <summary>
36 /// 取钱
37 /// </summary>
38 /// <param name="amount">取钱金额</param>
39 void WithdrawMoney(int amount);
40 }
41
42 public class ABank:IUnionPay
43 {
44 /// <summary>
45 /// 银行利率
46 /// </summary>
47 public double BankRate { get; set; }
48 public ABank(string name)
49 {
50 Console.WriteLine($"银行名称:{name}");
51 }
52 public void SaveMoneny(int amount)
53 {
54 Console.WriteLine($"把钱存入A银行(利率:{BankRate}%),金额为:{amount}");
55 }
56
57 public void WithdrawMoney(int amount)
58 {
59 Console.WriteLine($"从A银行取钱,金额为:{amount}");
60 }
61 }
62 }
当接口类有多个实现类,实现方式如下:
1 using Autofac;
2 using System;
3
4 namespace BankOperation
5 {
6 class Program
7 {
8 static void Main(string[] args)
9 {
10 Console.Write("请输入银行名称:");
11 string name = Console.ReadLine();
12 Operation(name);
13
14 Console.ReadKey();
15 }
16
17 static void Operation(string name)
18 {
19 // 创建 ContainerBuilder
20 ContainerBuilder builder = new ContainerBuilder();
21
22 // 注册(通过实例化函数传递参数+类的公共属性)
23 builder.Register(c => new ABank("测试A银行") { BankRate = 8.12 }).Named<IUnionPay>("A");
24 builder.Register(c => new ABank("测试B银行") { BankRate = 10.25 }).Named<IUnionPay>("B");
25
26 // 实例化
27 IContainer container = builder.Build();
28 var dev = container.ResolveNamed<IUnionPay>(name);
29 dev.SaveMoneny(80);
30 dev.WithdrawMoney(50);
31 }
32
33 }
34
35 public interface IUnionPay
36 {
37 /// <summary>
38 /// 存钱
39 /// </summary>
40 /// <param name="amount">存钱金额</param>
41 void SaveMoneny(int amount);
42
43 /// <summary>
44 /// 取钱
45 /// </summary>
46 /// <param name="amount">取钱金额</param>
47 void WithdrawMoney(int amount);
48 }
49
50 public class ABank:IUnionPay
51 {
52 /// <summary>
53 /// 银行利率
54 /// </summary>
55 public double BankRate { get; set; }
56 public ABank(string name)
57 {
58 Console.WriteLine($"银行名称:{name}");
59 }
60 public void SaveMoneny(int amount)
61 {
62 Console.WriteLine($"把钱存入A银行(利率:{BankRate}%),金额为:{amount}");
63 }
64
65 public void WithdrawMoney(int amount)
66 {
67 Console.WriteLine($"从A银行取钱,金额为:{amount}");
68 }
69 }
70
71 public class BBank : IUnionPay
72 {
73 /// <summary>
74 /// 银行利率
75 /// </summary>
76 public double BankRate { get; set; }
77 public BBank(string name)
78 {
79 Console.WriteLine($"银行名称:{name}");
80 }
81 public void SaveMoneny(int amount)
82 {
83 Console.WriteLine($"把钱存入B银行(利率:{BankRate}%),金额为:{amount}");
84 }
85
86 public void WithdrawMoney(int amount)
87 {
88 Console.WriteLine($"从B银行取钱,金额为:{amount}");
89 }
90 }
91 }
四、程序集注册
以上方法全部都要进行手动注册,如果有很多接口及实现类,这种一一注册的方式很麻烦,我们可以一次性全部注册,当然也可以加筛选条件。
1 using Autofac;
2 using System;
3 using System.Collections.Generic;
4 using System.Reflection;
5
6 namespace BankOperation
7 {
8 class Program
9 {
10 static void Main(string[] args)
11 {
12 Operation();
13
14 Console.ReadKey();
15 }
16
17 static void Operation()
18 {
19 // 创建 ContainerBuilder
20 ContainerBuilder builder = new ContainerBuilder();
21
22 //实现类所在的程序集名称
23 Assembly assembly = Assembly.Load("BankOperation");
24
25 // 获取程序集所在的全部实现类
26 builder.RegisterAssemblyTypes(assembly).AsImplementedInterfaces();
27
28 // t.Name.StartsWith:通过类名添加筛选条件,从类名的起始位开始匹配
29 builder.RegisterAssemblyTypes(assembly).Where(t => t.Name.StartsWith("B")).AsImplementedInterfaces();
30
31 // 实例化
32 IContainer container = builder.Build();
33 IEnumerable<IUnionPay> banks = container.Resolve<IEnumerable<IUnionPay>>();
34
35 foreach (var item in banks)
36 {
37 item.SaveMoneny(100);
38 item.WithdrawMoney(20);
39 Console.WriteLine("-----------------------------------------------");
40 }
41 }
42
43 }
44
45 public interface IUnionPay
46 {
47 /// <summary>
48 /// 存钱
49 /// </summary>
50 /// <param name="amount">存钱金额</param>
51 void SaveMoneny(int amount);
52
53 /// <summary>
54 /// 取钱
55 /// </summary>
56 /// <param name="amount">取钱金额</param>
57 void WithdrawMoney(int amount);
58 }
59
60 public class ABank:IUnionPay
61 {
62 public void SaveMoneny(int amount)
63 {
64 Console.WriteLine($"把钱存入A银行,金额为:{amount}");
65 }
66
67 public void WithdrawMoney(int amount)
68 {
69 Console.WriteLine($"从A银行取钱,金额为:{amount}");
70 }
71 }
72
73 public class BBank : IUnionPay
74 {
75 public void SaveMoneny(int amount)
76 {
77 Console.WriteLine($"把钱存入B银行,金额为:{amount}");
78 }
79
80 public void WithdrawMoney(int amount)
81 {
82 Console.WriteLine($"从B银行取钱,金额为:{amount}");
83 }
84 }
85 }
五、引用地址
1:Autofac官网地址:https://autofaccn.readthedocs.io/zh/latest/
2:Autofac 测试用例代码:https://github.com/autofac/Autofac