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

C#泛型类方法调用最佳实践:优化冗长switch实现高性能CRUD

高性能替代switch实现方案

针对泛型场景下按类型分发调用重载方法的需求,以下方案性能和手写硬编码switch基本持平,同时解决分支冗长、维护困难的问题,完全满足10万级对象的处理性能要求。

推荐方案:预编译表达式树+类型缓存

核心逻辑是将「业务类型 -> 对应处理逻辑」的映射在程序启动阶段一次性编译为强类型委托存入字典,运行时通过类型O(1)查找直接执行委托,没有任何运行时反射开销。

实现步骤

  1. 构建静态缓存容器,启动时注册所有业务类型的处理逻辑
using System.Collections.Concurrent;
using System.Linq.Expressions;

public static class EntityOperationCache
{
    // 缓存结构:业务类型 -> 调用对应CreateEntity重载的委托
    private static readonly ConcurrentDictionary<Type, Func<ObjBuilder, object, Entry>> _createHandlers = new();

    /// <summary>
    /// 程序启动时调用一次,注册所有需要处理的业务类型
    /// 后续新增业务类型只需要在这里加一行注册代码即可,无需修改核心调用逻辑
    /// </summary>
    public static void Init()
    {
        // 注册默认处理逻辑
        Register<Broke>();
        // 注册业务类型
        Register<Profile>();
        Register<Area>();
        Register<Credential>();
        Register<Device>();
        // 剩余20+业务类按相同格式追加即可
    }

    private static void Register<TEntity>()
    {
        // 用表达式树预编译强类型调用委托,性能和手写硬编码一致
        var builderParam = Expression.Parameter(typeof(ObjBuilder), "builder");
        var objParam = Expression.Parameter(typeof(object), "obj");
        var convertedObj = Expression.Convert(objParam, typeof(TEntity));
        var createCall = Expression.Call(
            instance: builderParam,
            methodName: nameof(ObjBuilder.CreateEntity),
            typeArguments: null,
            arguments: convertedObj);
        var handler = Expression.Lambda<Func<ObjBuilder, object, Entry>>(createCall, builderParam, objParam).Compile();
        _createHandlers[typeof(TEntity)] = handler;
    }

    /// <summary>
    /// 统一创建入口
    /// </summary>
    public static Entry ExecuteCreate(ObjBuilder builder, object entity)
    {
        var entityType = entity.GetType();
        // 未注册的类型走默认Broke逻辑
        if (!_createHandlers.TryGetValue(entityType, out var handler))
        {
            handler = _createHandlers[typeof(Broke)];
        }
        return handler(builder, entity);
    }

    // Update/Delete/Query三个CRUD操作可以按照完全相同的逻辑扩展缓存和方法,不需要重复写switch分支
}
  1. 替换原有的泛型方法实现,删除所有switch分支
public Entry Create<T>(T obj, ObjBuilder builder)
{
    return EntityOperationCache.ExecuteCreate(builder, obj);
}

方案优势

  • 性能:委托仅在启动时编译一次,运行时调用为直接方法调用开销,10万次执行耗时和手写switch差异在1ms以内,远高于反射、dynamic等方案的性能。
  • 维护性:30个业务类*4个CRUD操作仅需要在Init方法中完成注册,不需要在每个操作方法中维护上百个分支,新增类型时不会出现分支漏写的问题。

可选方案:泛型处理器自动注册

如果允许为每个业务类型新增独立处理器类,可以进一步降低维护成本,实现新增业务类型零修改核心代码:

  1. 定义统一处理器接口,包含所有CRUD操作方法
public interface IEntityProcessor<T>
{
    Entry Create(T entity, ObjBuilder builder);
    Entry Update(T entity, ObjBuilder builder);
    Entry Delete(T entity, ObjBuilder builder);
    Entry Query(T entity, ObjBuilder builder);
}
  1. 为每个业务类实现对应处理器,例如ProfileProcessor : IEntityProcessor<Profile>,内部直接调用builder对应的重载方法。
  2. 启动时通过程序集扫描自动查找所有IEntityProcessor<>的实现类,注册到类型缓存中,后续新增处理器不需要手动写注册代码,自动生效。
    该方案性能和上述预编译缓存方案完全一致,维护成本更低,适合业务类型后续持续迭代新增的场景。

不推荐方案说明

  • 纯反射调用:每次执行时动态查找方法元数据,单次调用开销是硬编码的10~100倍,10万次调用会产生百毫秒级的额外耗时,不适合高性能场景。
  • dynamic动态绑定:首次执行某类型时会做动态重载解析并缓存,首次调用开销高,且重载匹配逻辑不透明,出现参数匹配错误时排查成本极高。
  • 原生switch分支:类型数量超过10个后维护成本指数级上升,多CRUD场景下重复分支代码极多,容易出现漏写、错写分支的问题。

内容的提问来源于stack exchange,提问作者Justin Neff

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.29 22:18:56