當前位置:
首頁 > 知識 > 在netcore中如何注入同一個介面的多個實現

在netcore中如何注入同一個介面的多個實現

netcore中自帶了Ioc框架,這也影響了我們的編碼習慣,以前都是靜態類或者直接new對象,現在有了Ioc框架的支持,我們也不必守舊,應當使用起來,接受這種對象管理方式。使用過java的同仁,都習慣了Spring,感覺離開了Spring就好像失去了靈魂一樣。Spring經過多年的沉澱,非常的穩定和靈活,相比之下,netcore中自帶的Ioc框架太過輕量,中規中矩的使用還算夠用,但是其靈活性的確有待加強。比如屬性注入、欄位注入、方法參數注入等等,雖然說官方強烈建議使用構造函數注入,並且只提供了構造函數注入,但是我感覺後期肯定會支持更多都注入方法的,並且會結合Attribute提供更為靈活的功能,期望這一天能快點到來!

今天主要討論其中一個問題,就是如何在netcore中注入同一個介面的多個實現,註冊多個實現並不難,關鍵是如何優雅的取出來。下面我們用代碼來說話:

public interface IServiceA
{
string GetStr();
}
public class ImplA1 : IServiceA
{
public string GetStr()
{
return "ImplA1";
}
}
public class ImplA2 : IServiceA
{
public string GetStr()
{
return "ImplA2";
}
}

上面的代碼是有一個服務介面IServieA,和兩個不同的實現類。如果我們這樣註冊:

services.AddSingleton<IServiceA>(new ImplA1());
services.AddSingleton<IServiceA>(new ImplA2());

第一種使用方式:

public class HomeController : Controller
{
private readonly IServiceA serviceA;
public HomeController(IServiceA serviceA)
{
this.serviceA = serviceA; //這裡注入進來的是最後一個實現,也就是ImplA2
}
public IActionResult Index()
{
return Content(serviceA.GetStr());
}
}

這種方法肯定是不行的,因為只能獲取註冊的最後一個實現。

第二種使用方式:

public class HomeController : Controller
{
private readonly IServiceA serviceA;
public HomeController(IEnumerable<IServiceA> serviceAList)
{
this.serviceA = serviceAList.First(); //這裡注入進來的是一個非要服務集合
}
public IActionResult Index()
{
return Content(serviceA.GetStr());
}
}

這種方法也不好,需要自己在集合中篩選要想的實現。

其實我們更希望是這樣的,註冊的時候可以使用一個標識,然後使用Attribute指定標識來獲取具體的實現:

services.AddSingleton<IServiceA>("impla1",new ImplA1()); //impla1為該實現在該介面的唯一標識
services.AddSingleton<IServiceA>("impla2",new ImplA2()); //同上

可能會有這麼一個Attribute類:

public class IdentifierAttribute : Attribute
{
public IdentifierAttribute(string id)
{
this.Id = id;
}
public string Id { get; set; }
}

然後使用的時候大概是這樣:

public HomeController([Identifier("impla1")]IServiceA serviceA)
{
this.serviceA = serviceA; //根據Identifier的指定,這裡應該是ImplA1,
}

如果能像Spring中@Autowired註解,注入欄位就更好了:

[Autowired]
[Identifier("impla1")]
private readonly IServiceA serviceA;

然而,我們該醒醒了,netcore中自帶的Ioc沒有提供類似這樣的功能,我找了很久也沒找到。

作為程序員,我們都要具備一種特質,那就是愛思考,經過思考,我感覺可以使用工廠來解決這個問題。這裡只是提供一種思路和實現,有更好的方法大家可以留言討論。

首先我們定義一個用於存儲單例的集合類:

public class SingletonFactory
{
Dictionary<Type, Dictionary<string, object>> serviceDict;
public SingletonFactory()
{
serviceDict = new Dictionary<Type, Dictionary<string, object>>();
}
public TService GetService<TService>(string id) where TService : class
{
var serviceType = typeof(TService);
return GetService<TService>(serviceType, id);
}
public TService GetService<TService>(Type serviceType, string id) where TService : class
{
if (serviceDict.TryGetValue(serviceType, out Dictionary<string, object> implDict))
{
if (implDict.TryGetValue(id, out object service))
{
return service as TService;
}
}
return null;
}
public void AddService<TService>(TService service, string id) where TService : class
{
AddService(typeof(TService), service, id);
}
public void AddService(Type serviceType, object service, string id)
{
if (service != null)
{
if (serviceDict.TryGetValue(serviceType, out Dictionary<string, object> implDict))
{
implDict[id] = service;
}
else
{
implDict = new Dictionary<string, object>();
implDict[id] = service;
serviceDict[serviceType] = implDict;
}
}
}
}

這個類中使用一個嵌套的字典來存儲服務類的實現,提供添加服務和獲取服務的方法。

有了這樣一個類,在netcore自帶的Ioc中我們就可以獲取更多的控制權了。且看下面代碼。

註冊服務:

SingletonFactory singletonFactory = new SingletonFactory();
singletonFactory.AddService<IServiceA>(new ImplA1(), "impla1");
singletonFactory.AddService<IServiceA>(new ImplA2(), "impla2");
services.AddSingleton(singletonFactory);

我們把同一個介面的多個實現都加到SingletonFactory中,然後把SingletonFactory註冊到Ioc。

使用服務:

private readonly IServiceA serviceA;
public HomeController(SingletonFactory singletonFactory)
{
this.serviceA = singletonFactory.GetService<IServiceA>("impla2"); //使用標識從SingletonFactory獲取自己想要的服務實現
}

使用服務都時候我們注入SingletonFactory,然後從SingletonFactory根據標識獲取具體的服務實現。

這個方法還算優雅嗎?,目前來看我是可以接受了,不過還是希望官方能早些提供更強大更靈活的功能,期待netcore會越來越好!

在netcore中如何注入同一個介面的多個實現

打開今日頭條,查看更多圖片

作者:loogn

原文:https://www.cnblogs.com/loogn/p/10223977.html

喜歡這篇文章嗎?立刻分享出去讓更多人知道吧!

本站內容充實豐富,博大精深,小編精選每日熱門資訊,隨時更新,點擊「搶先收到最新資訊」瀏覽吧!


請您繼續閱讀更多來自 程序員小新人學習 的精彩文章:

springmvc訪問靜態資源的方式
應聘引擎程序需做哪些準備

TAG:程序員小新人學習 |