You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

C#实现RegisterHandlers 构造可执行Expression调用基类泛型Register方法

实现方案

先修正示例中的笔误

示例代码存在几处笔误,实现前需要先对齐:

  • MyWidget 继承的 Base 应为 WidgetBase
  • MyWidget 的构造函数名 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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.09.30 09:09:03