在 . Net framework 實現注入依賴
函數庫
在開發.net core專案的時候,如果要使用注入依賴的話可以透過nuget 安裝 Microsoft.Extensions.DependencyInjection
但是.net framework卻沒有官方的注入依賴容器的函數庫可以用,我們可以用第三方的函數庫-ninject
DI Container
指定介面、方法
透過DI容器取得注入依賴,在透過DI容器取得注入依賴的實例,實現依賴反轉原則
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32
| using Ninject; using System;
namespace ConsoleApp2 { class Program { public static void Main(string[] args) { IKernel Container = new StandardKernel(); Container.Bind<IAnimal>().To<Bird>(); IAnimal instance = Container.Get<Bird>(); instance.Bark(); Console.ReadLine(); }
public interface IAnimal { string Name { get; set; } void Bark(); }
public class Bird : IAnimal { public string Name { get; set; } public void Bark() { Console.WriteLine($"{Name} : joo"); } } } }
|
透過容器注入物件之間的依賴
如果沒有透過容器注入依賴的話,就要在主程式裡面new 兩個物件的實例,還要把Dog物件的實例丟到Leo物件裡面當做建構子的參數,如果今天物件數量很多或是參數很多的時候,就會不好維護
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34
| using System;
namespace ConsoleApp2 { class Program { public static void Main(string[] args) { Leo me = new Leo(new Dog()); me.ShowMyPet(); } } public class Leo { Dog _dog; public Leo(Dog dog) { _dog = dog; }
public void ShowMyPet() { _dog.Bark(); } }
public class Dog { public void Bark() { Console.WriteLine("woof"); } } }
|
如果透過容器注入依賴的話只要把需要的物件(Dog)注入到容器裡面,取得需要的物件(Leo)時,產生Leo物件實例的時候,Leo物件實例會去容器裡面找自己建構子需要的物件存不存在,存在的話自動把他取出來,但是如果不存在的話會發生例外
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54
| using Ninject; using System;
namespace ConsoleApp2 { class Program { static void Main(string[] args) { IKernel container = new StandardKernel(); container.Bind<IAnimal>().To<Dog>(); container.Bind<IPeople>().To<Leo>(); IPeople peopleInstance = container.Get<Leo>(); peopleInstance.ShowMyPet(); Console.ReadLine(); } } public interface IAnimal { void Bark(); }
public class Dog : IAnimal { public void Bark() { Console.WriteLine("woof"); } }
public interface IPeople { string Name { get; set; } void ShowMyPet(); }
public class Leo : IPeople { IAnimal _pet;
public Leo(IAnimal pet) { _pet = pet; }
public string Name { get; set; }
public void ShowMyPet() { _pet.Bark(); } } }
|
Multi Injection
Leo類別建構子參數是IAnimal陣列,只要把Leo類別需要的IAnimal跟對應的類別注入到DI容器中,在產生Leo類別實例的時候,就會自動把所有DI容器理符合條件的東西都產生出來
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59
| using Ninject; using System;
namespace ConsoleApp2 { class Program { static void Main(string[] args) { IKernel container = new StandardKernel(); container.Bind<IAnimal>().To<Dog>(); container.Bind<IAnimal>().To<Cat>(); IPeople peopleInstance = container.Get<Leo>(); peopleInstance.ShowAllPet(); Console.ReadLine(); } }
public interface IAnimal { void Barking(); }
public class Dog : IAnimal { public void Barking() { Console.WriteLine("Dog barking"); } }
public class Cat : IAnimal { public void Barking() { Console.WriteLine("Cat barking"); } }
public interface IPeople { void ShowAllPet(); }
public class Leo: IPeople { IAnimal[] _allAnimal; public Leo(IAnimal[] allAnimal) { _allAnimal = allAnimal; }
public void ShowAllPet() { foreach (var item in _allAnimal) item.Barking(); } } }
|
注入容器時設定屬性值
偶爾在產生物件實例的時候會希望可以先設定好某些屬性值,這時候可以使用 WithPropertyValue()方法
這邊要注意一定要Bind物件 to self才能正常產生物件實例不然從容器Get物件實例的時候會發生例外
1 2 3 4 5 6 7 8 9 10 11 12 13
| class Program { static void Main(string[] args) { IKernel container = new StandardKernel(); container.Bind<Dog>().ToSelf() .WithPropertyValue("Name", "coffee") .WithPropertyValue("Age", 2)
Dog instance = container.Get<Dog>(); Console.ReadLine(); } }
|
有設定屬性值當然也有設定建構子參數,這時候可以使用 WithConstructorArgument()方法
一樣要注意Bind物件to Self避免產生實力時發生例外
1 2 3 4 5 6 7 8 9 10 11 12 13
| class Program { static void Main(string[] args) { IKernel container = new StandardKernel(); container.Bind<Dog>().ToSelf() .WithConstructorArgument("Name", "coffee") .WithConstructorArgument("Age", 2);
Dog instance = container.Get<Dog>(); Console.ReadLine(); } }
|
幫注入容器中的物件命名
在某些情況下會在DI容器中注入好幾個一模一樣的類別,可能只有某個屬性值不一樣而已,這時候可以使用DI容器的Named()方法
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
| class Program { static void Main(string[] args) { IKernel container = new StandardKernel(); container.Bind<Dog>().Named("coffee") .WithConstructorArgument("Age", 1);
container.Bind<Dog>().Named("lulu") .WithConstructorArgument("Age", 2);
Dog coffeeInstance = container.Get<Dog>("coffee"); Dog luluInstance = container.Get<Dog>("lulu");
Console.ReadLine(); } }
|