動手造輪子:實現一個簡單的依賴注入(三) --- 支援屬性注入
阿新 • • 發佈:2020-06-10
# 動手造輪子:實現一個簡單的依賴注入(三) --- 支援屬性注入
## 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
-
-
-
-
-