1. 程式人生 > >動手造輪子:實現一個簡單的依賴注入(三) --- 支援屬性注入

動手造輪子:實現一個簡單的依賴注入(三) --- 支援屬性注入

# 動手造輪子:實現一個簡單的依賴注入(三) --- 支援屬性注入 ## Intro 前面寫了幾篇依賴注入的文章,有興趣的小夥伴可以參考文末 `Reference` 部分中的連結,一直有小夥伴希望增加屬性注入的支援,昨天試著加了一下,思路很簡單,在獲取到服務例項之後檢查例項中有沒有需要注入的屬性,如果有並且不為 `null` 就從服務容器中獲取一個對應屬性型別的例項 ## 程式碼修改 ### FromServiceAttribute > 完整的程式碼修改可以參考這個 commit 首先我們需要增加一個 `FromServiceAttribute` 用來標識哪些屬性需要注入,程式碼如下: ``` csharp [AttributeUsage(AttributeTargets.Property | AttributeTargets.Field | AttributeTargets.Parameter, AllowMultiple = false, Inherited = false)] public sealed class FromServiceAttribute : Attribute { } ``` 這裡 `AttributeTargets` 除了屬性之外增加了欄位和引數,是想可能以後會用到,引數典型的應用場景就是類似於 asp.net core 裡的 `[FromServices]` 用來實現方法注入引數 ### EnrichObject 增加了一個 `EnrichObject` 方法,用來在獲取到服務例項之後,對服務例項做一些補充的配置,如我們要加的屬性注入,如果我們要加欄位注入等也可以在這個方法內完成,來看實現: ``` csharp private object EnrichObject(object obj) { if (null != obj) { // PropertyInjection var type = obj.GetType(); foreach (var property in CacheUtil.TypePropertyCache.GetOrAdd(type, t =>
t.GetProperties()) .Where(x => x.IsDefined(typeof(FromServiceAttribute)))) { if (property.GetValueGetter()?.Invoke(obj) == null) { property.GetValueSetter()?.Invoke( obj, GetService(property.PropertyType) ); } } } return obj; } ``` 上面的邏輯就是獲取這個 object 定義的所有需要注入的屬性,如果屬性的值不為 null 則,從服務容器中獲取對應的服務例項,之所以要檢查是不是null 上面的 `CacheUtil.TypePropertyCache` 是一個 Type 為 key,PropertyInfo 陣列為 Value 的併發字典,用來快取型別的屬性 GetValueGetter/GetValueSetter 是 PropertyInfo 的擴充套件方法,利用表示式樹和快取提高屬性 Get/Set 的效率 ## GetSertviceInstance 修改原來的 GetServiceInstance 方法為 GetServiceInstanceInternal,增加一個一樣的方法,實現邏輯是在 GetServiceInstanceInternal 的基礎上呼叫上面的 Enrich 方法來實現屬性注入 ![](https://img2020.cnblogs.com/blog/489462/202006/489462-20200610080022383-972905473.png) ## More 雖然增加了屬性注入的支援,但是還是不太推薦使用,從上面屬性注入的程式碼中可以看得到,如果用不好很容易出現迴圈依賴的問題,而且用構造器注入的話依賴關係很清晰,分析方法的構造方法即可,如果要使用屬性注入請謹慎使用 ## Reference -
- - - -