在 .NetCore 內常常需要實作 DI ,但有時候會遇到兩個 Class 繼承同一個 Interface 的情況,這時在 Class 實作 Interface 依賴注入的時候,會發生不知道到底注入了哪一個實作的情況,當然也是可以直接注入 Class 不過這樣就少了 Interface 的好處。
遇到這種情況的時候,需要在介面跟實作動個手腳,才能在注入的時候指定要用哪個實作。
首先假設有一個 InterfaceA ,然後有兩個 Class 分別為 ClassA、ClassB 都是繼承 InterfaceA ,大致上會長這樣
public interface InterfaceA
{
void DoSomeThing();
}
public class ClassA:InterfaceA
{
public void DoSomthing()
{
//DoSomeThing
}
}
public class ClassB:InterfaceA
{
public void DoSomthing()
{
//DoSomeThing
}
}
接下來需要做個識別來當作注入的判斷依據,這邊我偏向新增一個Enum來作為判斷依據, 修改後大致會長得像這樣
public interface InterfaceA
{
TargetEnum target{get;}
void DoSomeThing();
}
public class ClassA:InterfaceA
{
public TargetEnum target => TargetEnum.TargetA
public void DoSomthing()
{
//DoSomeThing
}
}
public class ClassB:InterfaceA
{
public TargetEnum target => TargetEnum.TargetB
public void DoSomthing()
{
//DoSomeThing
}
}
public enum TargetEnum
{
TargetA,
TargetB
}
接下來在 Startup.cs 裡面宣告這兩項的依賴注入
public void ConfigureServices(IServiceCollection services)
{
...
services.AddScoped<InterfaceA, ClassA>();
services.AddScoped<InterfaceA, ClassB>();
...
}
最後使用時注入的方式跟一般稍微不同,如下
public class Service
{
IEnumerable<InterfaceA> _interfaceA;
public Service(IEnumerable<InterfaceA> interfaceA)
{
_interfaceA = interfaceA;
}
public void Worker()
{
//實作classA
var classA = _interfaceA.FirstOrDefault(s => s.target == TargetEnum.TargetA);
classA.DoSomthing();
//實作classB
var classB = _interfaceA.FirstOrDefault(s => s.target == TargetEnum.TargetB);
classB.DoSomthing();
}
}
如此就可以在繼承同一個 interface 的依賴注入情況下,分別實作不同的實作 Class 了。
這樣子是否造成了介面與物件之間的依賴呢?列舉需要明確了知道實作物件的名稱,後續在擴展物件時也需要一併修改列舉(產生了依賴),在使用端也需要明確知道自已要使用哪個物件(這也喪失了介面注入的特性),小弟認為不如一開始就注入類別吧。