Posted by Leo Yang on 2023-11-01
net-framework-注入依賴.md

在 . Net framework 實現注入依賴

函數庫

在開發.net core專案的時候,如果要使用注入依賴的話可以透過nuget 安裝 Microsoft.Extensions.DependencyInjection 但是.net framework卻沒有官方的注入依賴容器的函數庫可以用,我們可以用第三方的函數庫-ninject

Ninject

DI Container

指定介面、方法

透過DI容器取得注入依賴,在透過DI容器取得注入依賴的實例,實現依賴反轉原則

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物件裡面當做建構子的參數,如果今天物件數量很多或是參數很多的時候,就會不好維護

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物件實例會去容器裡面找自己建構子需要的物件存不存在,存在的話自動把他取出來,但是如果不存在的話會發生例外

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>(); //從DI容器中取出Leo物件實例,Leo物件實例自動在DI容器中找到需要的Dog物件 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容器理符合條件的東西都產生出來

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物件實例的時候會發生例外

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避免產生實力時發生例外

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()方法

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(); } }