Postsharp基本用法——方法、屬性攔截與異常處理


以下Demo代碼基於 .NET Core 演示了Postsharp的基本使用方法,稍作修改(反射部分有些許差異)也適用於.NET Framework。

更多高級使用方法詳見官方文檔。http://samples.postsharp.net/

 

代碼(注意,這段代碼編譯后會有警告,解決方案見文末):

  1 using System;
  2 using System.Linq;
  3 using PostSharp.Aspects;
  4 using PostSharp.Serialization;
  5 
  6 namespace NetCoreConsole
  7 {
  8   class Program
  9   {
 10     static void Main(string[] args)
 11     {
 12       var result = Calc(5, 6);
 13       Console.WriteLine($"計算結果:{result}");
 14       Console.WriteLine(">>>>>>>>>>>>>>方法攔截測試完畢\r\n");
 15 
 16 
 17       PropertyTest = -1;
 18       Console.WriteLine(">>>>>>>>>>>>>>屬性攔截測試(setter)完畢\r\n");
 19 
 20 
 21       var x = PropertyTest;
 22       Console.WriteLine(">>>>>>>>>>>>>>屬性攔截測試(getter)完畢\r\n");
 23 
 24       Console.ReadKey();
 25     }
 26 
 27 
 28     /// <summary>
 29     /// 方法攔截測試 + 異常處理
 30     /// </summary>
 31     /// <param name="x"></param>
 32     /// <param name="y"></param>
 33     /// <returns></returns>
 34     [HowToUse, ExceptionHandle]
 35     private static int Calc(int x, int y)
 36     {
 37       int a = 1;
 38       int b = 0;
 39       int c = a / b;
 40 
 41       return x + y;
 42     }
 43 
 44     private static int _propertyTest;
 45 
 46     /// <summary>
 47     /// 屬性攔截測試
 48     /// 注:可以標記在整個屬性上,也可以分別單獨標記在 【getter】 或者 【setter】 上
 49     /// </summary>
 50     [HowToUse, ExceptionHandle]
 51     private static int PropertyTest
 52     {
 53 
 54       get
 55       {
 56         return _propertyTest;
 57       }
 58 
 59       // [HowToUse]
 60       set
 61       {
 62         if (value <= 0)
 63         {
 64           throw new ArgumentException($"屬性值必須大於0");
 65         }
 66 
 67         _propertyTest = value;
 68       }
 69     }
 70   }
 71 }
 72 
 73 /// <summary>
 74 /// 方法攔截測試
 75 /// </summary>
 76 [PSerializable]
 77 [AttributeUsage(AttributeTargets.Method | AttributeTargets.Property)]
 78 public class HowToUseAttribute : MethodInterceptionAspect
 79 {
 80   /// <summary>
 81   /// 方法執行攔截
 82   /// </summary>
 83   /// <param name="args"></param>
 84   public override void OnInvoke(MethodInterceptionArgs args)
 85   {
 86     var methodBase = args.Method;
 87 
 88     // 如果是 .NET Framework 這里的System.Reflection.MethodInfo 應該替換為 System.Reflection.RuntimeMethodInfo
 89     var returnType = ((System.Reflection.MethodInfo)methodBase).ReturnType.FullName;
 90      
 91     // 方法形式參數列表字符
 92     var paramListString = methodBase.GetParameters().Aggregate(string.Empty,
 93       (current, parameter) => current + $"{parameter.ParameterType.FullName} {parameter.Name}, ").Trim(',', ' ');
 94 
 95     // 方法簽名
 96     // var signatures =  $"{returnType} {methodBase.Name}({paramListString})";
 97     var signatures = methodBase.ToString();
 98 
 99     Console.WriteLine($"被攔截的方法簽名:{signatures}");
100 
101     // 方法實際參數列表字符
102     var argsString = args.Arguments
103       .Aggregate(string.Empty, (current, p) => current + $"{p.GetType().FullName} ---> 值:{p}, ").Trim(',', ' ');
104 
105     Console.WriteLine($"被攔截的方法輸入參數:{argsString}");
106 
107     // 處理(執行被攔截的方法)
108     args.Proceed();
109 
110     // 異步執行
111     // args.ProceedAsync();
112 
113     var returnValue = args.ReturnValue;
114 
115     Console.WriteLine($"方法返回值:{returnValue}");
116   }
117 }
118 
119 /// <summary>
120 /// 異常處理
121 /// </summary>
122 [PSerializable]
123 [AttributeUsage(AttributeTargets.Method | AttributeTargets.Property)]
124 public class ExceptionHandleAttribute : OnExceptionAspect
125 {
126   public override void OnException(MethodExecutionArgs args)
127   {
128     // 設置流程行為(繼續執行,不拋出)
129     args.FlowBehavior = FlowBehavior.Continue;
130 
131     Console.WriteLine($"發生異常:{args.Exception.GetType().FullName} ----> {args.Exception.Message}");
132   }
133 }

 

這段代碼可以正常編譯,但會有警告。警告內容類似下圖:

 

            (圖1)

 

大意就是說在我們的 Calc方法上存在沖突的切面。

為什么會產生這樣的警告呢,因為我們使用了兩個類型的Aspect,一個是異常處理,一個是方法攔截(屬性也可以認為是Getter和Setter兩個方法的結合)。 

異常處理切面(Aspect)期望包裝我們的目標方法,方法攔截切面(Aspect)也是如此,但是這兩個切面並不是強排序的,它們的執行順序並不確定,這就是沖突。解決方法很簡單,請對比圖2與圖3中代碼的區別:

              (圖2)

 

               (圖3)

 

 

沒錯,解決方法就是使用 [  AspectPriority  ]屬性手動指定切面的優先順序。屬性值是Int類型,可以隨意設置,值越小優先級越高,只要讓引擎能從數字層面區分優先順序即可。

另外,切面的優先順序不一樣,引擎最終編譯出來的代碼也是不一樣的,具體可以反編譯查看。不管誰先執行誰后執行,總的來說結果沒什么變化的。我個人更喜歡將異常處理切面優先級提高些,這樣更加符合平時手寫代碼的風格。

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM