首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> .NET 網頁程式設計 >> C# >> 關於C#

C# 擴展方法進階實戰:Type 類型擴展工具箱

     編輯:關於C#

前言

System.Type 提供豐富反射功能,但在處理泛型類型 (可空類型、集合介面) 時仍有缺口。本文打造 TypeHelper 擴展類別,補強泛型類型判斷與元素類型提取能力。

核心擴展方法

using System;
using System.Collections.Generic;
using System.Reflection;

public static class TypeHelper
{
    // 判斷是否為可空類型 (Nullable<T>)
    public static bool IsNullableType(this Type type)
        => type != null && type.IsGenericType && type.GetGenericTypeDefinition() == typeof(Nullable<>);

    // 取得可空類型的底層類型 (int? -> int)
    public static Type GetNonNullableType(this Type type)
        => IsNullableType(type) ? type.GetGenericArguments()[0] : type;

    // 判斷是否實作 IEnumerable<T> (泛型集合)
    public static bool IsEnumerableType(this Type type)
        => FindGenericType(typeof(IEnumerable<>), type) != null;

    // 取得 IEnumerable<T> 的元素類型
    public static Type GetElementType(this Type type)
    {
        var genericType = FindGenericType(typeof(IEnumerable<>), type);
        return genericType != null ? genericType.GetGenericArguments()[0] : type;
    }

    // 判斷是否為某泛型定義的實作 (如 List<string> 是 IEnumerable<> 的一種)
    public static bool IsKindOfGeneric(this Type type, Type genericDefinition)
        => FindGenericType(genericDefinition, type) != null;

    // 核心遞迴搜尋:在型別繼承鏈與介面中尋找符合的泛型定義
    private static Type FindGenericType(Type definition, Type type)
    {
        while (type != null && type != typeof(object))
        {
            if (type.IsGenericType && type.GetGenericTypeDefinition() == definition)
                return type;

            if (definition.IsInterface)
            {
                foreach (var iface in type.GetInterfaces())
                {
                    var found = FindGenericType(definition, iface);
                    if (found != null) return found;
                }
            }
            type = type.BaseType;
        }
        return null;
    }
}

單元測試驗證

[TestClass]
public class TypeHelperTests
{
    [TestMethod]
    public void NullableTypeTests()
    {
        Assert.IsTrue(typeof(int?).IsNullableType());
        Assert.IsFalse(typeof(int).IsNullableType());
        Assert.IsTrue(typeof(Nullable<DateTime>).IsNullableType());
        Assert.AreEqual(typeof(int), typeof(int?).GetNonNullableType());
        Assert.AreEqual(typeof(DateTime), typeof(Nullable<DateTime>).GetNonNullableType());
    }

    [TestMethod]
    public void EnumerableTypeTests()
    {
        Assert.IsTrue(typeof(IEnumerable<string>).IsEnumerableType());
        Assert.IsTrue(typeof(List<int>).IsEnumerableType());
        Assert.IsTrue(typeof(Collection<DateTime>).IsEnumerableType());
        Assert.AreEqual(typeof(int), typeof(IEnumerable<int>).GetElementType());
        Assert.AreEqual(typeof(DateTime), typeof(Collection<DateTime>).GetElementType());
    }

    [TestMethod]
    public void GenericKindTests()
    {
        Assert.IsTrue(typeof(List<string>).IsKindOfGeneric(typeof(IEnumerable<>)));
        Assert.IsTrue(typeof(string).IsKindOfGeneric(typeof(IComparable<>)));
        Assert.AreEqual(typeof(IEnumerable<string>), typeof(List<string>).FindGenericType(typeof(IEnumerable<>)));
    }
}

進階應用場景

  1. 模型繫結器:自動識別動作參數是否為集合、可空類型,正確處理表單資料。
  2. 序列化器:根據元素類型選擇序列化策略 (陣列 vs 物件)。
  3. 依賴注入容器:掃描泛型介面實作 (如 IRepository<T>) 進行自動註冊。
  4. 動態程式碼生成:分析泛型委派簽章生成對應 IL。

注意事項

  • IsEnumerableType/GetElementType 僅針對 IEnumerable<T>,非泛型 IEnumerable (如 ArrayList) 會回傳 false/原型別。
  • 陣列類型 (int[]) 實作 IEnumerable<T>,可正常運作。
  • 效能敏感場合建議快取 FindGenericType 結果。

結語

這組 Type 擴展方法解決了泛型類型分析的常見痛點,是建構反射密集型框架 (MVC、WebAPI、ORM、DI 容器) 的利器。記得搭配單元測試確保邊界條件正確處理。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved