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

C# 字串類型驗證擴展方法:統一判斷 IsInt、IsBool、IsDateTime 等類型

     編輯:關於.NET

前言

在 Web 開發中,頻繁需要驗證來自前端的字串參數是否可轉換為 int、bool、DateTime 等類型。標準做法是 int.TryParse(str, out var val),但每次都要宣告 out 變數,且需針對每種類型寫重複代碼。本文利用 C# 擴展方法 + 反射,實現通用 string.Is<T>(),一次解決所有實作 IConvertible 且擁有 TryParse(string, out T) 靜態方法的類型驗證。

核心實現

using System;
using System.Reflection;
using System.Security;

public static class TypeValidate
{
    /// 
    /// 判斷字串是否可轉換為類型 T
    /// T 必須:1. 實作 IConvertible  2. 擁有無參建構函數  3. 擁有靜態方法 bool TryParse(string, out T)
    /// 
    [SecuritySafeCritical]
    public static bool Is<T>(this string value) where T : IConvertible
    {
        var type = typeof(T);
        // TryParse 第二參數為 out T,反射需用 MakeByRefType
        var types = new Type[] { typeof(string), type.MakeByRefType() };
        var method = type.GetMethod("TryParse", types);

        if (method == null)
            throw new TryParseException($"Type {type.Name} does not have a suitable TryParse(string, out T) method.");

        try
        {
            // 建立 T 實例作為 out 參數佔位 (TryParse 為靜態方法,實例不影響調用)
            T instance = Activator.CreateInstance<T>();
            // Invoke 靜態方法,傳入 null 作為 instance
            object[] args = new object[] { value, instance };
            bool result = (bool)method.Invoke(null, args);
            return result;
        }
        catch (Exception ex)
        {
            throw new TryParseException($"TryParse invocation failed for {type.Name}.", ex);
        }
    }
}

public class TryParseException : Exception
{
    public TryParseException() : base() { }
    public TryParseException(string message) : base(message) { }
    public TryParseException(string message, Exception inner) : base(message, inner) { }
}

使用示例

string input = "123";
if (input.Is<int>()) { /* ... */ }

if ("true".Is<bool>()) { /* ... */ }

if ("2023-12-25".Is<DateTime>()) { /* ... */ }

// 支援所有內建實作 TryParse 的類型:byte, short, long, float, double, decimal, Guid, TimeSpan, Enum 等
if ("42".Is<byte>()) { /* ... */ }
if ("3.14".Is<double>()) { /* ... */ }
if ("Guid".Is<Guid>()) { /* false */ }

關鍵技術點解析

  1. 泛型約束 where T : IConvertible:縮小適用範圍至內建基礎類型,確保語義清晰。
  2. type.MakeByRefType():TryParse 第二參數為 out T,對應 CLR 的 byref 類型,反射查找方法時必須指定 typeof(string), type.MakeByRefType(),否則 GetMethod 返回 null。
  3. Activator.CreateInstance<T>():建立實例僅為滿足 Invoke 參數陣列長度,TryParse 為靜態方法,實際不使用該實例。
  4. method.Invoke(null, args):靜態方法調用傳 null 作為目標實例。
  5. 自定義異常 TryParseException:區分「類型不支援」與「轉換失敗」,調用方可選擇捕獲或向上拋出。

擴展:支援自定義類型

若自定義結構體 struct MyInt { public static bool TryParse(string s, out MyInt result) { ... } } 實作 IConvertible,同樣可用 str.Is<MyInt>()。

效能考量

  • 反射有一定開銷,高頻熱路徑建議緩存 MethodInfo (用 ConcurrentDictionary<Type, MethodInfo>)。
  • 對於固定類型 (int, bool, DateTime),直接調用 int.TryParse 仍是最快。
  • 此擴展適合「類型在運行時確定」或「通用驗證管道」場景 (如模型綁定器、配置解析器)。

總結

string.Is<T>() 以極少代碼統一了所有基礎類型的字串驗證邏輯,消除重複 TryParse 樣板代碼,提升代碼可讀性與維護性。結合反射動態查找 TryParse,體現了 C# 泛型與反射結合的靈活威力。

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