自定义拦截器

1.自定义特性标记:通过 ExceptionInterceptorAttribute 标记需要进行异常处理的方法,并可通过属性配置处理方式
 1 using System;
 2 
 3 /// <summary>
 4 /// 标记需要进行异常拦截的方法
 5 /// </summary>
 6 [AttributeUsage(AttributeTargets.Method, Inherited = true)]
 7 public class ExceptionInterceptorAttribute : Attribute
 8 {
 9     // 可以添加属性配置异常处理方式
10     public bool LogException { get; set; } = true;
11     public bool RethrowException { get; set; } = true;
12 }
13     
View Code

2.动态代理生成:

使用 System.Reflection.Emit 命名空间下的类动态生成代理类

代理类实现目标接口,并持有原始对象的引用

在生成的代理方法中加入 try-catch 块实现异常拦截

  1 using System;
  2 using System.Reflection;
  3 using System.Reflection.Emit;
  4 
  5 /// <summary>
  6 /// 代理生成器,用于创建带有异常处理的代理类
  7 /// </summary>
  8 public static class ProxyGenerator
  9 {
 10     /// <summary>
 11     /// 创建带有异常拦截的代理实例
 12     /// </summary>
 13     public static T CreateProxy<T>(T target) where T : class
 14     {
 15         if (target == null)
 16             throw new ArgumentNullException(nameof(target));
 17 
 18         // 获取接口类型
 19         Type interfaceType = typeof(T);
 20         if (!interfaceType.IsInterface)
 21             throw new InvalidOperationException("目标类型必须是接口");
 22 
 23         // 创建动态程序集和模块
 24         AssemblyName assemblyName = new AssemblyName("DynamicProxyAssembly");
 25         AssemblyBuilder assemblyBuilder = AssemblyBuilder.DefineDynamicAssembly(
 26             assemblyName, AssemblyBuilderAccess.Run);
 27         ModuleBuilder moduleBuilder = assemblyBuilder.DefineDynamicModule("DynamicProxyModule");
 28 
 29         // 定义代理类
 30         TypeBuilder typeBuilder = moduleBuilder.DefineType(
 31             $"{interfaceType.Name}Proxy",
 32             TypeAttributes.Public | TypeAttributes.Class);
 33         
 34         // 实现目标接口
 35         typeBuilder.AddInterfaceImplementation(interfaceType);
 36 
 37         // 添加目标对象字段
 38         FieldBuilder targetField = typeBuilder.DefineField(
 39             "_target", interfaceType, FieldAttributes.Private);
 40 
 41         // 生成构造函数
 42         GenerateConstructor(typeBuilder, targetField);
 43 
 44         // 实现接口方法
 45         ImplementInterfaceMethods(typeBuilder, interfaceType, targetField);
 46 
 47         // 创建类型并实例化
 48         Type proxyType = typeBuilder.CreateType();
 49         return Activator.CreateInstance(proxyType, target) as T;
 50     }
 51 
 52     // 生成构造函数
 53     private static void GenerateConstructor(TypeBuilder typeBuilder, FieldBuilder targetField)
 54     {
 55         ConstructorInfo baseCtor = typeof(object).GetConstructor(Type.EmptyTypes);
 56         ConstructorBuilder ctorBuilder = typeBuilder.DefineConstructor(
 57             MethodAttributes.Public, CallingConventions.Standard, 
 58             new[] { targetField.FieldType });
 59 
 60         ILGenerator il = ctorBuilder.GetILGenerator();
 61         il.Emit(OpCodes.Ldarg_0);
 62         il.Emit(OpCodes.Call, baseCtor);
 63         il.Emit(OpCodes.Ldarg_0);
 64         il.Emit(OpCodes.Ldarg_1);
 65         il.Emit(OpCodes.Stfld, targetField);
 66         il.Emit(OpCodes.Ret);
 67     }
 68 
 69     // 实现接口的所有方法
 70     private static void ImplementInterfaceMethods(TypeBuilder typeBuilder, Type interfaceType, FieldBuilder targetField)
 71     {
 72         foreach (MethodInfo method in interfaceType.GetMethods())
 73         {
 74             ImplementMethod(typeBuilder, method, targetField);
 75         }
 76     }
 77 
 78     // 实现单个方法,添加异常处理逻辑
 79     private static void ImplementMethod(TypeBuilder typeBuilder, MethodInfo method, FieldBuilder targetField)
 80     {
 81         // 检查方法是否有异常拦截特性
 82         bool hasInterceptor = method.IsDefined(typeof(ExceptionInterceptorAttribute), true);
 83         if (!hasInterceptor)
 84         {
 85             // 没有标记特性的方法直接调用目标对象方法
 86             ImplementNormalMethod(typeBuilder, method, targetField);
 87             return;
 88         }
 89 
 90         // 获取特性配置
 91         var attribute = method.GetCustomAttribute<ExceptionInterceptorAttribute>();
 92 
 93         // 定义方法参数类型
 94         Type[] parameterTypes = method.GetParameters()
 95             .Select(p => p.ParameterType)
 96             .ToArray();
 97 
 98         // 定义代理方法
 99         MethodBuilder methodBuilder = typeBuilder.DefineMethod(
100             method.Name,
101             MethodAttributes.Public | MethodAttributes.Virtual,
102             method.ReturnType,
103             parameterTypes);
104 
105         // 实现方法调用和异常处理
106         ILGenerator il = methodBuilder.GetILGenerator();
107 
108         // 创建异常处理块
109         Label tryStart = il.BeginExceptionBlock();
110 
111         // 调用目标对象的方法
112         il.Emit(OpCodes.Ldarg_0);
113         il.Emit(OpCodes.Ldfld, targetField);
114         
115         // 加载方法参数
116         for (int i = 0; i < parameterTypes.Length; i++)
117         {
118             il.Emit(OpCodes.Ldarg, i + 1);
119         }
120         
121         il.Emit(OpCodes.Callvirt, method);
122 
123         // 正常退出
124         il.Emit(OpCodes.Leave, tryStart);
125 
126         // 异常处理
127         il.BeginCatchBlock(typeof(Exception));
128         
129         // 存储异常对象到局部变量
130         LocalBuilder exception = il.DeclareLocal(typeof(Exception));
131         il.Emit(OpCodes.Stloc, exception);
132 
133         // 记录异常日志
134         if (attribute.LogException)
135         {
136             il.Emit(OpCodes.Ldstr, $"方法 {method.DeclaringType.Name}.{method.Name} 发生异常: {{{0}}}");
137             il.Emit(OpCodes.Ldloc, exception);
138             il.Emit(OpCodes.Callvirt, typeof(Exception).GetProperty("Message").GetGetMethod());
139             il.Emit(OpCodes.Call, typeof(string).GetMethod("Format", new[] { typeof(string), typeof(object) }));
140             il.Emit(OpCodes.Call, typeof(Console).GetMethod("WriteLine", new[] { typeof(string) }));
141         }
142 
143         // 重新抛出异常
144         if (attribute.RethrowException)
145         {
146             il.Emit(OpCodes.Ldloc, exception);
147             il.Emit(OpCodes.Throw);
148         }
149         else
150         {
151             // 如果不重新抛出,对于有返回值的方法需要返回默认值
152             if (method.ReturnType != typeof(void))
153             {
154                 il.Emit(OpCodes.Ldnull);
155             }
156         }
157 
158         // 结束异常块
159         il.EndExceptionBlock();
160         il.Emit(OpCodes.Ret);
161 
162         // 将方法与接口方法关联
163         typeBuilder.DefineMethodOverride(methodBuilder, method);
164     }
165 
166     // 实现没有异常拦截的方法
167     private static void ImplementNormalMethod(TypeBuilder typeBuilder, MethodInfo method, FieldBuilder targetField)
168     {
169         Type[] parameterTypes = method.GetParameters()
170             .Select(p => p.ParameterType)
171             .ToArray();
172 
173         MethodBuilder methodBuilder = typeBuilder.DefineMethod(
174             method.Name,
175             MethodAttributes.Public | MethodAttributes.Virtual,
176             method.ReturnType,
177             parameterTypes);
178 
179         ILGenerator il = methodBuilder.GetILGenerator();
180         
181         // 直接调用目标对象的方法
182         il.Emit(OpCodes.Ldarg_0);
183         il.Emit(OpCodes.Ldfld, targetField);
184         
185         for (int i = 0; i < parameterTypes.Length; i++)
186         {
187             il.Emit(OpCodes.Ldarg, i + 1);
188         }
189         
190         il.Emit(OpCodes.Callvirt, method);
191         il.Emit(OpCodes.Ret);
192 
193         typeBuilder.DefineMethodOverride(methodBuilder, method);
194     }
195 }
196     
View Code

3.异常处理逻辑:

记录异常信息(方法名、异常消息等)

根据配置决定是否重新抛出异常

对有返回值的方法提供默认返回值支持

 1 using System;
 2 
 3 // 1. 定义服务接口
 4 public interface IOrderService
 5 {
 6     [ExceptionInterceptor(LogException = true, RethrowException = true)]
 7     void CreateOrder(int orderId, string customerName);
 8     
 9     [ExceptionInterceptor(LogException = true, RethrowException = false)]
10     decimal CalculateTotal(decimal price, int quantity);
11     
12     // 这个方法不会被拦截
13     string GetOrderStatus(int orderId);
14 }
15 
16 // 2. 实现服务
17 public class OrderService : IOrderService
18 {
19     public void CreateOrder(int orderId, string customerName)
20     {
21         if (orderId <= 0)
22             throw new ArgumentException("订单ID必须大于0", nameof(orderId));
23             
24         if (string.IsNullOrEmpty(customerName))
25             throw new ArgumentNullException(nameof(customerName), "客户名称不能为空");
26             
27         Console.WriteLine($"订单 {orderId} 创建成功,客户: {customerName}");
28     }
29     
30     public decimal CalculateTotal(decimal price, int quantity)
31     {
32         if (price < 0)
33             throw new InvalidOperationException("价格不能为负数");
34             
35         if (quantity <= 0)
36             throw new ArgumentOutOfRangeException(nameof(quantity), "数量必须大于0");
37             
38         return price * quantity;
39     }
40     
41     public string GetOrderStatus(int orderId)
42     {
43         // 这个方法没有标记特性,不会被拦截
44         if (orderId <= 0)
45             throw new ArgumentException("无效的订单ID");
46             
47         return "已完成";
48     }
49 }
50 
51 // 3. 使用示例
52 class Program
53 {
54     static void Main(string[] args)
55     {
56         // 创建原始服务实例
57         IOrderService originalService = new OrderService();
58         
59         // 创建带有异常拦截的代理服务
60         IOrderService proxyService = ProxyGenerator.CreateProxy(originalService);
61         
62         try
63         {
64             // 测试有拦截的方法
65             proxyService.CreateOrder(1001, "张三");
66             proxyService.CalculateTotal(99.9m, 5);
67             
68             // 测试异常情况
69             proxyService.CreateOrder(-1, null); // 会记录并重新抛出异常
70         }
71         catch (Exception ex)
72         {
73             Console.WriteLine($"捕获到异常: {ex.Message}");
74         }
75         
76         try
77         {
78             // 这个异常不会被重新抛出(RethrowException = false)
79             proxyService.CalculateTotal(-100, 5);
80         }
81         catch (Exception ex)
82         {
83             Console.WriteLine($"这里不会被执行,因为异常没有被重新抛出: {ex.Message}");
84         }
85         
86         try
87         {
88             // 这个方法没有拦截器,异常会直接抛出
89             proxyService.GetOrderStatus(-1);
90         }
91         catch (Exception ex)
92         {
93             Console.WriteLine($"未拦截的方法抛出异常: {ex.Message}");
94         }
95     }
96 }
97     
View Code

 

posted @ 2025-08-27 23:05  小码哥-风云  阅读(5)  评论(0)    收藏  举报