.NET Core反射獲取帶有自定義特性的類,透過依賴注入根據Attribute後設資料資訊呼叫對應的方法

追逐時光者發表於2023-04-15

前言

  前段時間有朋友問道一個這樣的問題,.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();
    }

輸出如下:

 

相關文章