前言
前段時間有朋友問道一個這樣的問題,.NET Core中如何透過Attribute的後設資料資訊來呼叫標記的對應方法。我第一時間想到的就是透過C#反射獲取帶有Custom Attribute標記的類,然後透過依賴注入(DI)的方式獲取對應服務的方法並透過反射動態執行類的方法,從而實現更靈活的程式設計方式。
C#中反射指的是什麼?
開篇之前首先和大家簡單介紹一下反射的概念和作用。
在 C# 中,反射是指在執行時動態地獲取型別的資訊並操作物件的能力。使用反射,我們可以在程式碼中訪問程式集、模組、成員等,並且可以操作這些成員的屬性、方法、欄位和事件等。
自定義一個Attribute型別
/// <summary> /// 自定義一個Attribute型別 /// </summary> [AttributeUsage(AttributeTargets.Class, AllowMultiple = false)] public class CustomAttribute : Attribute { public string TargetMethod { get; set; } public CustomAttribute(string targetMethod) { TargetMethod = targetMethod; } }
定義如下兩個需要被執行的服務,並使用CustomAttribute標記
/// <summary> /// 前進服務 /// </summary> [Custom("AdvanceWay")] public class AdvanceService { public void AdvanceWay() { Console.WriteLine("On the move!"); } } /// <summary> /// 後退服務 /// </summary> [Custom("RetreatWay")] public class RetreatService { public void RetreatWay() { Console.WriteLine("Be retreating!"); } }
註冊需要注入的服務
var services = new ServiceCollection(); //註冊需要注入的服務 services.AddTransient<AdvanceService>(); services.AddTransient<RetreatService>();
反射獲取所有帶有CustomAttribute特性的類並呼叫對應方法
static void Main(string[] args) { var services = new ServiceCollection(); //註冊需要注入的服務 services.AddTransient<AdvanceService>(); services.AddTransient<RetreatService>(); var provider = services.BuildServiceProvider(); #region 反射獲取所有帶有CustomAttribute特性的類並呼叫對應方法 //反射獲取所有帶有CustomAttribute特性的類 var classes = Assembly.GetExecutingAssembly().GetTypes() .Where(type => type.GetCustomAttributes<CustomAttribute>().Any()); foreach (var clazz in classes) { //獲取標記CustomAttribute的例項 var attr = clazz.GetCustomAttributes<CustomAttribute>().First(); //根據CustomAttribute後設資料資訊呼叫對應的方法 var methodInfo = clazz.GetMethod(attr.TargetMethod); if (methodInfo != null) { //instance 物件是透過依賴注入容器獲取的。這是一種常用的實現方式,可以使用依賴注入解耦程式中各個元件之間的依賴關係,方便測試和維護。 var instance = provider.GetService(clazz); methodInfo.Invoke(instance, null); } } #endregion #region 反射獲取所有帶有CustomAttribute特性的類並呼叫指定方法 var executionMethod = "RetreatWay"; foreach (var clazz in classes) { //獲取標記CustomAttribute的例項 var attr = clazz.GetCustomAttributes<CustomAttribute>().First(); if (attr.TargetMethod == executionMethod) { //根據CustomAttribute後設資料資訊呼叫對應的方法 var methodInfo = clazz.GetMethod(attr.TargetMethod); if (methodInfo != null) { //instance 物件是透過依賴注入容器獲取的。這是一種常用的實現方式,可以使用依賴注入解耦程式中各個元件之間的依賴關係,方便測試和維護。 var instance = provider.GetService(clazz); methodInfo.Invoke(instance, null); } } } #endregion Console.ReadLine(); }
輸出如下: