• 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类型,可以随意设置,值越小优先级越高,只要让引擎能从数字层面区分优先顺序即可。

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

  • 相关阅读:
    家里蹲大学数学杂志期刊模式目录
    [历朝通俗演义-蔡东藩-前汉]第008回 葬始皇骊山成巨冢 戮宗室豻狱构奇冤
    [历朝通俗演义-蔡东藩-前汉]第007回 寻生路徐市垦荒 从逆谋李斯矫诏
    [历朝通俗演义-蔡东藩-前汉]第006回 阬深谷诸儒毙命 得原璧暴主惊心
    [历朝通俗演义-蔡东藩-前汉]第005回 信佞臣尽毁诗书 筑阿房大兴土木
    [历朝通俗演义-蔡东藩-前汉]第004回 误椎击逃生遇异士 见图谶遣将造长城
    [历朝通俗演义-蔡东藩-前汉]第003回 封泰岱下山避雨 过湘江中渡惊风
    [历朝通俗演义-蔡东藩]
    [历朝通俗演义-蔡东藩-前汉]第002回 诛假父纳言迎母 称皇帝立法愚民
    [历朝通俗演义-蔡东藩-前汉]第001回 移花接木计献美姬 用李代桃欢承淫后
  • 原文地址:https://www.cnblogs.com/WinHEC/p/Postsharp_Basic_Usage.html
Copyright © 2020-2023  润新知