关于.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官网地址://autofaccn.readthedocs.io/zh/latest/

2:Autofac 测试用例代码://github.com/autofac/Autofac

3:相关博文:关于.NET中的控制反转(二)- 依赖注入之 MEF关于.NET中的控制反转(一)- 概念与定义

Tags: