zoukankan      html  css  js  c++  java
  • 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(">>>>>>>>>>>>>>方法拦截测试完毕
    ");
     15 
     16 
     17       PropertyTest = -1;
     18       Console.WriteLine(">>>>>>>>>>>>>>属性拦截测试(setter)完毕
    ");
     19 
     20 
     21       var x = PropertyTest;
     22       Console.WriteLine(">>>>>>>>>>>>>>属性拦截测试(getter)完毕
    ");
     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类型,可以随意设置,值越小优先级越高,只要让引擎能从数字层面区分优先顺序即可。

    另外,切面的优先顺序不一样,引擎最终编译出来的代码也是不一样的,具体可以反编译查看。不管谁先执行谁后执行,总的来说结果没什么变化的。我个人更喜欢将异常处理切面优先级提高些,这样更加符合平时手写代码的风格。

  • 相关阅读:
    Java实现 蓝桥杯 算法训练 画图(暴力)
    Java实现 蓝桥杯 算法训练 画图(暴力)
    Java实现 蓝桥杯 算法训练 相邻数对(暴力)
    Java实现 蓝桥杯 算法训练 相邻数对(暴力)
    Java实现 蓝桥杯 算法训练 相邻数对(暴力)
    Java实现 蓝桥杯 算法训练 Cowboys
    Java实现 蓝桥杯 算法训练 Cowboys
    55. Jump Game
    54. Spiral Matrix
    50. Pow(x, n)
  • 原文地址:https://www.cnblogs.com/WinHEC/p/Postsharp_Basic_Usage.html
Copyright © 2011-2022 走看看