關于.NET Attribute在數(shù)據(jù)校驗中的應用教程
前言
Attribute(特性)的概念不在此贅述了,相信有點.NET基礎的開發(fā)人員都明白,用過Attribute的人也不在少數(shù),畢竟很多框架都提供自定義的屬性,類似于Newtonsoft.JSON中JsonProperty、JsonIgnore等
自定義特性
.NET 框架允許創(chuàng)建自定義特性,用于存儲聲明性的信息,且可在運行時被檢索。該信息根據(jù)設計標準和應用程序需要,可與任何目標元素相關。
創(chuàng)建并使用自定義特性包含四個步驟:
- 聲明自定義特性
- 構建自定義特性
- 在目標程序元素上應用自定義特性
- 通過反射訪問特性
聲明自定義特性
一個新的自定義特性必須派生自System.Attribute類,例如:
public class FieldDescriptionAttribute : Attribute
{
public string Description { get; private set; }
public FieldDescriptionAttribute(string description)
{
Description = description;
}
}
public class UserEntity
{
[FieldDescription("用戶名稱")]
public string Name { get; set; }
}
該如何拿到我們標注的信息呢?這時候需要使用反射獲取
var type = typeof(UserEntity);
var properties = type.GetProperties();
foreach (var item in properties)
{
if(item.IsDefined(typeof(FieldDescriptionAttribute), true))
{
var attribute = item.GetCustomAttribute(typeof(FieldDescriptionAttribute)) as FieldDescriptionAttribute;
Console.WriteLine(attribute.Description);
}
}
執(zhí)行結(jié)果如下:

從執(zhí)行結(jié)果上看,我們拿到了我們想要的數(shù)據(jù),那么這個特性在實際使用過程中,到底有什么用途呢?
Attribute特性妙用
在實際開發(fā)過程中,我們的系統(tǒng)總會提供各種各樣的對外接口,其中參數(shù)的校驗是必不可少的一個環(huán)節(jié)。然而沒有特性時,校驗的代碼是這樣的:
public class UserEntity
{
/// <summary>
/// 姓名
/// </summary>
[FieldDescription("用戶名稱")]
public string Name { get; set; }
/// <summary>
/// 年齡
/// </summary>
public int Age { get; set; }
/// <summary>
/// 地址
/// </summary>
public string Address { get; set; }
}
UserEntity user = new UserEntity();
if (string.IsNullOrWhiteSpace(user.Name))
{
throw new Exception("姓名不能為空");
}
if (user.Age <= 0)
{
throw new Exception("年齡不合法");
}
if (string.IsNullOrWhiteSpace(user.Address))
{
throw new Exception("地址不能為空");
}
字段多了之后這種代碼就看著非常繁瑣,并且看上去不直觀。對于這種繁瑣又惡心的代碼,有什么方法可以優(yōu)化呢?
使用特性后的驗證寫法如下:
首先定義一個基礎的校驗屬性,提供基礎的校驗方法
public abstract class AbstractCustomAttribute : Attribute
{
/// <summary>
/// 校驗后的錯誤信息
/// </summary>
public string ErrorMessage { get; set; }
/// <summary>
/// 數(shù)據(jù)校驗
/// </summary>
/// <param name="value"></param>
public abstract void Validate(object value);
}
然后可以定義常用的一些對應的校驗Attribute,例如RequiredAttribute、StringLengthAttribute
/// <summary>
/// 非空校驗
/// </summary>
[AttributeUsage(AttributeTargets.Property)]
public class RequiredAttribute : AbstractCustomAttribute
{
public override void Validate(object value)
{
if (value == null || string.IsNullOrWhiteSpace(value.ToString()))
{
throw new Exception(string.IsNullOrWhiteSpace(ErrorMessage) ? "字段不能為空" : ErrorMessage);
}
}
}
/// <summary>
/// 自定義驗證,驗證字符長度
/// </summary>
[AttributeUsage(AttributeTargets.Property)]
public class StringLengthAttribute : AbstractCustomAttribute
{
private int _maxLength;
private int _minLength;
public StringLengthAttribute(int minLength, int maxLength)
{
this._maxLength = maxLength;
this._minLength = minLength;
}
public override void Validate(object value)
{
if (value != null && value.ToString().Length >= _minLength && value.ToString().Length <= _maxLength)
{
return;
}
throw new Exception(string.IsNullOrWhiteSpace(ErrorMessage) ? $"字段長度必須在{_minLength}與{_maxLength}之間" : ErrorMessage);
}
}
添加一個用于校驗的ValidateExtensions
public static class ValidateExtensions
{
/// <summary>
/// 校驗
/// </summary>
/// <typeparam name="T"></typeparam>
/// <returns></returns>
public static void Validate<T>(this T entity) where T : class
{
Type type = entity.GetType();
foreach (var item in type.GetProperties())
{
//需要對Property的字段類型做區(qū)分處理針對Object List 數(shù)組需要做區(qū)分處理
if (item.PropertyType.IsPrimitive || item.PropertyType.IsEnum || item.PropertyType.IsValueType || item.PropertyType == typeof(string))
{
//如果是基元類型、枚舉類型、值類型或者字符串 直接進行校驗
CheckProperty(entity, item);
}
else
{
//如果是引用類型
var value = item.GetValue(entity, null);
CheckProperty(entity, item);
if (value != null)
{
if ((item.PropertyType.IsGenericType && Array.Exists(item.PropertyType.GetInterfaces(), t => t.GetGenericTypeDefinition() == typeof(IList<>))) || item.PropertyType.IsArray)
{
//判斷IEnumerable
var enumeratorMI = item.PropertyType.GetMethod("GetEnumerator");
var enumerator = enumeratorMI.Invoke(value, null);
var moveNextMI = enumerator.GetType().GetMethod("MoveNext");
var currentMI = enumerator.GetType().GetProperty("Current");
int index = 0;
while (Convert.ToBoolean(moveNextMI.Invoke(enumerator, null)))
{
var currentElement = currentMI.GetValue(enumerator, null);
if (currentElement != null)
{
currentElement.Validate();
}
index++;
}
}
else
{
value.Validate();
}
}
}
}
}
private static void CheckProperty(object entity, PropertyInfo property)
{
if (property.IsDefined(typeof(AbstractCustomAttribute), true))//此處是重點
{
//此處是重點
foreach (AbstractCustomAttribute attribute in property.GetCustomAttributes(typeof(AbstractCustomAttribute), true))
{
if (attribute == null)
{
throw new Exception("AbstractCustomAttribute not instantiate");
}
attribute.Validate(property.GetValue(entity, null));
}
}
}
}
新的實體類
public class UserEntity
{
/// <summary>
/// 姓名
/// </summary>
[Required]
public string Name { get; set; }
/// <summary>
/// 年齡
/// </summary>
public int Age { get; set; }
/// <summary>
/// 地址
/// </summary>
[Required]
public string Address { get; set; }
[StringLength(11, 11)]
public string PhoneNum { get; set; }
}
調(diào)用方式
UserEntity user = new UserEntity(); user.Validate();
上面的校驗邏輯寫的比較復雜,主要是考慮到對象中包含復雜對象的情況,如果都是簡單對象,可以不用考慮,只需針對單個屬性做字段校驗
現(xiàn)有的方式是在校驗不通過的時候拋出異常,此處大家也可以自定義異常來表示校驗的問題,也可以返回自定義的校驗結(jié)果實體來記錄當前是哪個字段出的問題,留待大家自己實現(xiàn)
如果您有更好的建議和想法歡迎提出,共同進步
總結(jié)
到此這篇關于.NET Attribute在數(shù)據(jù)校驗中的應用的文章就介紹到這了,更多相關.NET Attribute在數(shù)據(jù)校驗的應用內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關文章希望大家以后多多支持腳本之家!
相關文章
用javascript為DropDownList控件下拉式選擇添加一個Item至定義索引位置
用Javascript為DropDownList控件下拉式選擇添加一個Item至定義索引位置;準備數(shù)據(jù),創(chuàng)建一個對象,將是存儲DropDownList控件每個Item數(shù)據(jù)2013-01-01
利用ASP.NET MVC+Bootstrap搭建個人博客之打造清新分頁Helper(三)
這篇文章主要介紹了利用ASP.NET MVC+Bootstrap搭建個人博客之打造清新分頁Helper(三)的相關資料,非常不錯,具有參考借鑒價值,需要的朋友可以參考下2016-06-06
Asp.net+jquery+.ashx文件實現(xiàn)分頁思路
分頁思路: .ashx程序中,編寫好取得不同頁碼的程序。在頁面布局好的前提下,留下數(shù)據(jù)區(qū)域 div。然后在頁面請求 .ashx程序生成下一頁的html代碼。覆蓋div.innerHTMl2013-03-03
ASP.NET MVC 開發(fā)微信支付H5的實現(xiàn)示例(外置瀏覽器支付)
這篇文章主要介紹了ASP.NET MVC 開發(fā)微信支付H5的實現(xiàn)示例(外置瀏覽器支付),文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習學習吧2019-12-12
CorFlags.exe檢查.NET程序平臺目標(Platform Target)的工具
.NET Framework SDK中的一個工具程序: CorFlags.exe。CorFlags.exe不但可查詢.NET組件的平臺目標設定,甚至能直接修改設定,省去重新編譯的工夫。2013-02-02

