C#实现RegisterHandlers 构造可执行Expression调用基类泛型Register方法
实现方案
先修正示例中的笔误
示例代码存在几处笔误,实现前需要先对齐:
MyWidget继承的Base应为WidgetBaseMyWidget的构造函数名MyClass应为MyWidget- 需先定义标记用的特性:
public class HandlerAttribute : Attribute { }
纯反射实现
代码逻辑简单易懂,适合调用频率不高的场景:
using System.Reflection; using System.Linq; public static class Ext { // 缓存Register方法的元数据,避免每次重复反射获取 private static readonly MethodInfo _registerMethod = typeof(WidgetBase) .GetMethod("Register", BindingFlags.Instance | BindingFlags.NonPublic)!; public static void RegisterHandlers<T>(this T t) { // 类型校验,确保继承自WidgetBase if (t is not WidgetBase widget) throw new ArgumentException($"类型 {typeof(T).FullName} 未继承自WidgetBase", nameof(t)); var type = t.GetType(); // 筛选所有符合要求的Handler方法 var handlerMethods = type.GetMethods(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic) .Where(m => m.GetCustomAttribute<HandlerAttribute>() != null && m.ReturnType == typeof(void) && m.GetParameters().Length == 1) .ToList(); foreach (var method in handlerMethods) { var messageType = method.GetParameters()[0].ParameterType; // 构造对应消息类型的Action委托 var delegateType = typeof(Action<>).MakeGenericType(messageType); var handler = Delegate.CreateDelegate(delegateType, t, method); // 构造泛型版本的Register方法并调用 var genericRegister = _registerMethod.MakeGenericMethod(messageType); genericRegister.Invoke(widget, new object[] { handler }); } } }
Expression优化实现(性能更高)
通过表达式树编译+类型缓存,性能接近手写代码,适合高频调用场景:
using System.Linq.Expressions; using System.Reflection; using System.Collections.Concurrent; public static class Ext { private static readonly MethodInfo _registerMethod = typeof(WidgetBase) .GetMethod("Register", BindingFlags.Instance | BindingFlags.NonPublic)!; // 类型级缓存,同类型的实例只会生成一次注册逻辑 private static readonly ConcurrentDictionary<Type, Action<WidgetBase>> _registerCache = new(); public static void RegisterHandlers<T>(this T t) { if (t is not WidgetBase widget) throw new ArgumentException($"类型 {typeof(T).FullName} 未继承自WidgetBase", nameof(t)); var registerAction = _registerCache.GetOrAdd(widget.GetType(), BuildRegisterDelegate); registerAction(widget); } private static Action<WidgetBase> BuildRegisterDelegate(Type widgetType) { var instanceParam = Expression.Parameter(typeof(WidgetBase), "w"); var convertedInstance = Expression.Convert(instanceParam, widgetType); var handlerMethods = widgetType.GetMethods(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic) .Where(m => m.GetCustomAttribute<HandlerAttribute>() != null && m.ReturnType == typeof(void) && m.GetParameters().Length == 1); var callExpressions = new List<Expression>(); foreach (var method in handlerMethods) { var messageType = method.GetParameters()[0].ParameterType; // 构造Action<TMessage>委托表达式 var msgParam = Expression.Parameter(messageType); var handlerDelegate = Expression.Lambda( typeof(Action<>).MakeGenericType(messageType), Expression.Call(convertedInstance, method, msgParam), msgParam ); // 构造Register<TMessage>方法调用 var genericRegister = _registerMethod.MakeGenericMethod(messageType); callExpressions.Add(Expression.Call(convertedInstance, genericRegister, handlerDelegate)); } // 把所有注册逻辑编译为统一委托 return Expression.Lambda<Action<WidgetBase>>( Expression.Block(callExpressions), instanceParam ).Compile(); } }
内容的提问来源于stack exchange,提问作者MarkkuL
相关产品推荐
相关产品推荐

