特性与方法注入
好久沒寫文章了,主要是前面一段時間比較忙,一直沒空學習和思考,好不容易找了個休息日,寫一下Blog
??? 前幾篇已經寫到過特性,并且用它實現了一些東西。這次來談一下一種比較怪異的特性的運用——方法注入。
??? 其實,說他怪異,稍微過了點,因為就連M$給大家的類庫就用這種運用,舉個例子TransactionAttribute,就是一個對事務相關方法的一個行為指導的注入。為什么這么說,TransactionAttribute可以定義強制開始一個新的事務或者使用已經存在的事務,或者定義事務的隔離級別。但是,特性本身什么事情也不能做,必須由別的類來讀去這個特性,由別的類根據這個特性做某些事,TransactionAttribute為什么會起作用?原因是在事務處理時,處理函數會創建一個StackTrace,通過查找當前堆棧上的方法的TransactionAttribute,獲得相關的事務信息,通過這些,事務處理函數就以期望的方式工作了。(因為特性標記在某個直接或間接調用到事務的方法上,所以執行事務的時候,這個方法一定在這個堆棧上)
??? 利用這個原理,可以做出一種類似的,利用特性注入方法的方式。這里就以最簡單的驗證參數為例:
????1、創建一個驗證特性,作為所有驗證特性的基類:
????public?abstract?class?ValidateAttribute?:?Attribute
????{
????????protected?ValidateAttribute()?{?}
????????public?abstract?void?Validate(object?value);
????}
????2、創建一個過濾空引用的驗證特性:
????[AttributeUsage(AttributeTargets.Method,?AllowMultiple?=?false,?Inherited?=?false)]
????public?sealed?class?NonNullValidateAttribute
????????:?ValidateAttribute
????{
????????public?NonNullValidateAttribute()
????????????:?base()?{?}
????????
????????public?override?void?Validate(object?value)
????????{
????????????if?(value?==?null)
????????????????throw?new?ArgumentNullException();
????????}
????}
????3、下一步,創建一個驗證方法:
????public?static?class?Validator
????{
????????public?static?void?Validate(object?value)
????????{
????????????StackFrame?sf?=?new?StackFrame(1,?false);
????????????MethodBase?m?=?sf.GetMethod();
????????????object[]?attrs?=?m.GetCustomAttributes(typeof(ValidateAttribute),?false);
????????????foreach?(ValidateAttribute?attr?in?attrs)
????????????{
????????????????attr.Validate(value);
????????????}
????????}
????}
????4、用起來看看吧
????????static?object?_testField;
????????static?void?Main(string[]?args)
????????{
????????????try
????????????{
????????????????TestProp?=?null;
????????????????Console.WriteLine(TestProp);
????????????}
????????????catch?(Exception?ex)
????????????{
????????????????Console.WriteLine(ex.Message);
????????????}
????????????Console.ReadLine();
????????}
????????static?object?TestProp
????????{
????????????get?{?return?_testField;?}
????????????[NonNullValidate()]
????????????set
????????????{
????????????????Validator.Validate(value);
????????????????_testField?=?value;
????????????}
????????}
????跑起來看看,看到了什么?對了ArgumentNullException的默認Message,Validator.Validate并沒有任何顯式的拋出這個異常,那么為什么會檢測出這個空參數哪?
????原因在于Validator.Validate檢查了當前調用堆棧中前一個方法(當前方法就是Validator.Validate自身),也就是調用Validator.Validate方法的方法,讀去這個方法中所有繼承自ValidateAttribute的特性,調用它們的Validate方法,例子中,只有一個NonNullValidate特性,它的Validate方法判斷了傳入的Value是否為空,如果未空就拋出異常。
????同樣,如果一個簡單的非空驗證不夠時,可能新寫一個特性類,繼承自ValidateAttribute,在需要的驗證的方法上添加這個特性就完成了。
????這么做的好處是什么?
????很簡單,代碼看起來清楚,修改更簡單。
????因為,不需要在代碼中可以避免很多 “if什么什么 throw什么什么”,代碼看起來就是,驗證什么變量,然后用這個變量什么什么干活。當大家不關心如何驗證時,就不會出現大段大段的驗證代碼,污染大家的視覺了,使要修改的代碼更容易找到。反過來,如果關心驗證,就看在這個方法上有些什么特性(當然特性的名字要取的好一點,弄個一串稀奇古怪的字符串,反而更看不懂),如果發現驗證用錯了,或者缺了什么驗證,修改一下方法上的特性就可以了。
????另一方面,這樣驗證代碼也可以重用起來,例如做了個英文大小寫的驗證特性,就可以直接在每一個需要這種驗證的方法上添加這個特性,而不需要每個方法自己實現。
????凡事總是有兩面的,說完優點,說說缺點,這個方式非常的靈活,但是代價是反射,在性能要求高于靈活要求的時候,這種方式就不適合了。
??? 前幾篇已經寫到過特性,并且用它實現了一些東西。這次來談一下一種比較怪異的特性的運用——方法注入。
??? 其實,說他怪異,稍微過了點,因為就連M$給大家的類庫就用這種運用,舉個例子TransactionAttribute,就是一個對事務相關方法的一個行為指導的注入。為什么這么說,TransactionAttribute可以定義強制開始一個新的事務或者使用已經存在的事務,或者定義事務的隔離級別。但是,特性本身什么事情也不能做,必須由別的類來讀去這個特性,由別的類根據這個特性做某些事,TransactionAttribute為什么會起作用?原因是在事務處理時,處理函數會創建一個StackTrace,通過查找當前堆棧上的方法的TransactionAttribute,獲得相關的事務信息,通過這些,事務處理函數就以期望的方式工作了。(因為特性標記在某個直接或間接調用到事務的方法上,所以執行事務的時候,這個方法一定在這個堆棧上)
??? 利用這個原理,可以做出一種類似的,利用特性注入方法的方式。這里就以最簡單的驗證參數為例:
????1、創建一個驗證特性,作為所有驗證特性的基類:
????public?abstract?class?ValidateAttribute?:?Attribute
????{
????????protected?ValidateAttribute()?{?}
????????public?abstract?void?Validate(object?value);
????}
????2、創建一個過濾空引用的驗證特性:
????[AttributeUsage(AttributeTargets.Method,?AllowMultiple?=?false,?Inherited?=?false)]
????public?sealed?class?NonNullValidateAttribute
????????:?ValidateAttribute
????{
????????public?NonNullValidateAttribute()
????????????:?base()?{?}
????????
????????public?override?void?Validate(object?value)
????????{
????????????if?(value?==?null)
????????????????throw?new?ArgumentNullException();
????????}
????}
????3、下一步,創建一個驗證方法:
????public?static?class?Validator
????{
????????public?static?void?Validate(object?value)
????????{
????????????StackFrame?sf?=?new?StackFrame(1,?false);
????????????MethodBase?m?=?sf.GetMethod();
????????????object[]?attrs?=?m.GetCustomAttributes(typeof(ValidateAttribute),?false);
????????????foreach?(ValidateAttribute?attr?in?attrs)
????????????{
????????????????attr.Validate(value);
????????????}
????????}
????}
????4、用起來看看吧
????????static?object?_testField;
????????static?void?Main(string[]?args)
????????{
????????????try
????????????{
????????????????TestProp?=?null;
????????????????Console.WriteLine(TestProp);
????????????}
????????????catch?(Exception?ex)
????????????{
????????????????Console.WriteLine(ex.Message);
????????????}
????????????Console.ReadLine();
????????}
????????static?object?TestProp
????????{
????????????get?{?return?_testField;?}
????????????[NonNullValidate()]
????????????set
????????????{
????????????????Validator.Validate(value);
????????????????_testField?=?value;
????????????}
????????}
????跑起來看看,看到了什么?對了ArgumentNullException的默認Message,Validator.Validate并沒有任何顯式的拋出這個異常,那么為什么會檢測出這個空參數哪?
????原因在于Validator.Validate檢查了當前調用堆棧中前一個方法(當前方法就是Validator.Validate自身),也就是調用Validator.Validate方法的方法,讀去這個方法中所有繼承自ValidateAttribute的特性,調用它們的Validate方法,例子中,只有一個NonNullValidate特性,它的Validate方法判斷了傳入的Value是否為空,如果未空就拋出異常。
????同樣,如果一個簡單的非空驗證不夠時,可能新寫一個特性類,繼承自ValidateAttribute,在需要的驗證的方法上添加這個特性就完成了。
????這么做的好處是什么?
????很簡單,代碼看起來清楚,修改更簡單。
????因為,不需要在代碼中可以避免很多 “if什么什么 throw什么什么”,代碼看起來就是,驗證什么變量,然后用這個變量什么什么干活。當大家不關心如何驗證時,就不會出現大段大段的驗證代碼,污染大家的視覺了,使要修改的代碼更容易找到。反過來,如果關心驗證,就看在這個方法上有些什么特性(當然特性的名字要取的好一點,弄個一串稀奇古怪的字符串,反而更看不懂),如果發現驗證用錯了,或者缺了什么驗證,修改一下方法上的特性就可以了。
????另一方面,這樣驗證代碼也可以重用起來,例如做了個英文大小寫的驗證特性,就可以直接在每一個需要這種驗證的方法上添加這個特性,而不需要每個方法自己實現。
????凡事總是有兩面的,說完優點,說說缺點,這個方式非常的靈活,但是代價是反射,在性能要求高于靈活要求的時候,這種方式就不適合了。
總結
- 上一篇: 收到猎头信息的一些感想
- 下一篇: 转贴一篇关于NAT(DNAT)以及PAT