假設現在有一個學生類(Student)
/// <summary>
/// 學生類
/// </summary>
public class Student
{
/// <summary>
/// 名字
/// </summary>
private string name;
public string Name
{
get { return name; }
set { name = value; }
}
/// <summary>
/// 年齡
/// </summary>
public int Age { get; set; }
/// <summary>
/// 地址
/// </summary>
public string Address { get; set; }
/// <summary>
/// 性別
/// </summary>
public string Sex;
}
如果需要判斷某些字段(屬性)是否為空,是否大於0,便有以下代碼:
public static string ValidateStudent(Student student)
{
StringBuilder validateMessage = new StringBuilder();
if (string.IsNullOrEmpty(student.Name))
{
validateMessage.Append("名字不能為空");
}
if (string.IsNullOrEmpty(student.Sex))
{
validateMessage.Append("性別不能為空");
}
if (student.Age <= 0)
{
validateMessage.Append("年齡必填大於0");
}
//...... 幾百行
// 寫到這裡發現不對啊,如果必填項有20多個,難道我要一直這樣寫嗎!
return validateMessage.ToString();
}
這樣的代碼,重用性不高,而且效率低。
我們可以用特性,反射,然後遍歷屬性並檢查特性。
首先自定義一個【必填】特性類,繼承自Attribute
/// <summary>
/// 【必填】特性,繼承自Attribute
/// </summary>
public sealed class RequireAttribute : Attribute
{
private bool isRequire;
public bool IsRequire
{
get { return isRequire; }
}
/// <summary>
/// 構造函數
/// </summary>
/// <param name="isRequire"></param>
public RequireAttribute(bool isRequire)
{
this.isRequire = isRequire;
}
}
然後用這個自定義的特性標記學生類的成員屬性:
/// <summary>
/// 學生類
/// </summary>
public class Student
{
/// <summary>
/// 名字
/// </summary>
private string name;
[Require(true)]
public string Name
{
get { return name; }
set { name = value; }
}
/// <summary>
/// 年齡
/// </summary>
[Require(true)]
public int Age { get; set; }
/// <summary>
/// 地址
/// </summary>
[Require(false)]
public string Address { get; set; }
/// <summary>
/// 性別
/// </summary>
[Require(true)]
public string Sex;
}
通過特性檢查類的屬性:
/// <summary>
/// 檢查方法,支持泛型
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="instance"></param>
/// <returns></returns>
public static string CheckRequire<T>(T instance)
{
var validateMsg = new StringBuilder();
//獲取T類的屬性
Type t = typeof (T);
var propertyInfos = t.GetProperties();
//遍歷屬性
foreach (var propertyInfo in propertyInfos)
{
//檢查屬性是否標記了特性
RequireAttribute attribute = (RequireAttribute) Attribute.GetCustomAttribute(propertyInfo, typeof (RequireAttribute));
//沒標記,直接跳過
if (attribute == null)
{
continue;
}
//獲取屬性的數據類型
var type = propertyInfo.PropertyType.ToString().ToLower();
//獲取該屬性的值
var value = propertyInfo.GetValue(instance);
if (type.Contains("system.string"))
{
if (string.IsNullOrEmpty((string) value) && attribute.IsRequire)
validateMsg.Append(propertyInfo.Name).Append("不能為空").Append(",");
}
else if (type.Contains("system.int"))
{
if ((int) value == 0 && attribute.IsRequire)
validateMsg.Append(propertyInfo.Name).Append("必須大於0").Append(",");
}
}
return validateMsg.ToString();
}
執行驗證:
static void Main(string[] args)
{
var obj = new Student()
{
Name = ""
};
Console.WriteLine(CheckRequire(obj));
Console.Read();
}
結果輸出:

有人會發現,Sex也標記了[Require(true)],為什麼沒有驗證信息,這是因為,Sex沒有實現屬性{ get; set; },GetProperties是獲取不到的。