關於.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: