.NET中特性+反射 實現資料校驗

梦想航路發表於2024-05-21

.NET中特性+反射 實現資料校驗

在.NET中,我們可以使用特性+反射來實現資料校驗。特性是一種用於為程式中的程式碼新增後設資料的機制。後設資料是與程式中的程式碼相關聯的資料,但不直接成為程式碼的一部分。透過特性,我們可以為類、方法、屬性等新增額外的資訊,這些資訊可以在執行時透過反射獲取和使用。
對反射不太熟悉的小夥伴可以去看我以前的文章 .NET中的反射

為了實現資料校驗,我們可以定義一個自定義特性,並將其應用於需要校驗的屬性或引數上。然後,我們可以編寫程式碼來檢查這些特性,並根據特性的配置執行相應的校驗邏輯。

示例程式碼

定義自定義特性

using System;
using System.ComponentModel.DataAnnotations;

[AttributeUsage(AttributeTargets.Property, Inherited = true, AllowMultiple = false)]
public class ValidationAttribute : Attribute 
{  
    public string ErrorMessage { get; set; }
  
    public ValidationAttribute(string errorMessage)  
    {  
        ErrorMessage = errorMessage;  
    }
}

定義具體的校驗特性

[AttributeUsage(AttributeTargets.Property, Inherited = true, AllowMultiple = false)]
public class RequiredAttribute : ValidationAttribute  
{  
    public RequiredAttribute() : base("該欄位是必填項。") { }  
}  
  
[AttributeUsage(AttributeTargets.Property, Inherited = true, AllowMultiple = false)]
public class RangeAttribute : ValidationAttribute  
{  
    public int Minimum { get; set; }  
    public int Maximum { get; set; }
  
    public RangeAttribute(int minimum, int maximum, string errorMessage = "該欄位的值必須在 {0} 和 {1} 之間。")   
        : base(errorMessage)  
    {  
        Minimum = minimum;  
        Maximum = maximum;  
    }
}

在模型類中使用這些特性

public class Person  
{  
    [Required]
    public string Name { get; set; }
  
    [Range(18, 100, ErrorMessage = "年齡必須在 18 到 100 之間。")]
    public int Age { get; set; }
}

編寫驗證方法

public class Validator  
{  
    public static bool Validate<T>(T obj, out string errorMessage)  
    {  
        errorMessage = null;  
        var type = typeof(T);  
        var properties = type.GetProperties();  
  
        foreach (var property in properties)  
        {  
            var validationAttributes = property.GetCustomAttributes(typeof(ValidationAttribute), true);  
  
            foreach (var attribute in validationAttributes)  
            {  
                var value = property.GetValue(obj);  
  
                switch (attribute)  
                {  
                    case RequiredAttribute required:  
                        if (value == null || (value is string str && string.IsNullOrWhiteSpace(str)))  
                        {  
                            errorMessage = required.ErrorMessage;  
                            return false;  
                        }  
                        break;  
                    case RangeAttribute range:  
                        if (value is IComparable comparable)  
                        {  
                            if (comparable.CompareTo(range.Minimum) < 0 || comparable.CompareTo(range.Maximum) > 0)  
                            {  
                                errorMessage = string.Format(range.ErrorMessage, range.Minimum, range.Maximum);  
                                return false;  
                            }  
                        }  
                        break;  
                    // 可以新增更多校驗特性型別  
                }  
            }  
        }  
  
        return true;  
    }  
}

使用Validator類來校驗Person物件

class Program
{
    static void Main(string[] args)
    {
        var person = new Person { Name = "張三", Age = 15 };
        string errorMessage;
        bool isValid = Validator.Validate(person, out errorMessage);
        if (!isValid)
        {
            Console.WriteLine(errorMessage); // 輸出:該欄位是必填項。
        }
        Console.ReadLine();
    }
}

說明

這個示例演示瞭如何使用特性和反射實現基本的資料校驗。在實際應用中,你可能需要處理更復雜的校驗邏輯和更多的校驗型別。

此外,還可以使用現有的資料特性(如System.ComponentModel.DataAnnotations名稱空間中的特性)來簡化校驗過程。
以下是該名稱空間中一些常用的特性(Attribute),以及它們的用途:

特性名稱 用途
[Required] 確保屬性值不為空(不為 null 且對於字串不是空字串)。
[StringLength] 限制字串屬性的最大長度。
[Range] 確保數值型屬性在指定的範圍內。
[Minimum] 確保數值型屬性不小於指定的最小值。
[Maximum] 確保數值型屬性不大於指定的最大值。
[RegularExpression] 透過正規表示式驗證屬性值的格式。
[EmailAddress] 驗證屬性值是否為有效的電子郵件地址。
[Url] 驗證屬性值是否為有效的 URL。
[Phone] 驗證屬性值是否為有效的電話號碼。
[CreditCard] 驗證屬性值是否為有效的信用卡號。
[Compare] 比較兩個屬性值是否相等,常用於密碼和確認密碼的欄位。
[DataType] 指定資料的型別,例如日期、時間、電話號碼等,並不驗證資料,而是提供給資料繫結機制。
[CustomValidation] 允許指定自定義驗證邏輯。
[EnumDataType] 驗證屬性值是否為指定列舉型別中的有效成員。
[StringLength] 驗證字串長度是否在指定的範圍內。

這些特性通常與ASP.NET Core或是ASP.NET MVC、Entity Framework等框架結合使用。
使用這些特性可以大大簡化資料驗證的程式碼,並且使驗證邏輯與業務邏輯分離,提高程式碼的可維護性和可讀性。

相關文章