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

如何用Lambda表达式实现反射创建对象,替代Activator.CreateInstance提升性能?

用编译后的Lambda表达式替代Activator.CreateInstance提升对象创建性能

如果你一直在用Activator.CreateInstance通过反射创建对象,肯定遇到过它的性能瓶颈——每次调用都要走反射流程,开销不小。而用编译后的Lambda表达式来生成对象实例,能把反射的开销降到最低:第一次编译Lambda后,后续调用都是直接的委托执行,性能提升非常显著。

我自己实现了一个静态工具类ClassBuilder,专门用来处理这种场景,代码完整实现如下:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Linq.Expressions;
using System.Reflection;

public static class ClassBuilder
{
    private delegate T ObjectActivator<T>(params object[] args);
    private static readonly Dictionary<(Type Type, Type[] ParamTypes), Delegate> _activatorCache = new Dictionary<(Type, Type[]), Delegate>();

    /// <summary>
    /// 此函数将创建T类型的具体对象
    /// </summary>
    /// <typeparam name="T">要返回的对象的基类或具体类型</typeparam>
    /// <param name="type">要创建的对象的具体类型</param>
    /// <param name="parameters">传递给构造函数的参数</param>
    /// <returns>具体对象的实例</returns>
    public static T CreateInstance<T>(Type type, params object[] parameters)
    {
        if (type == null)
        {
            throw new ArgumentNullException(nameof(type));
        }
        if (parameters == null)
        {
            throw new ArgumentNullException(nameof(parameters));
        }

        // 获取给定参数的具体类型
        Type[] typedArgs = parameters.Select(p => p.GetType()).ToArray();
        var cacheKey = (type, typedArgs);

        // 优先从缓存获取已编译的激活器
        if (_activatorCache.TryGetValue(cacheKey, out var activator))
        {
            return ((ObjectActivator<T>)activator)(parameters);
        }

        // 根据参数获取对应的构造函数
        ConstructorInfo ctor = type.GetConstructor(typedArgs);
        if (ctor != null)
        {
            // 创建并编译激活器Lambda
            ObjectActivator<T> createdActivator = GetActivator<T>(ctor);
            // 存入缓存复用
            _activatorCache[cacheKey] = createdActivator;
            return createdActivator(parameters);
        }
        else
        {
            throw new ArgumentException($"无法找到类型 {type.FullName} 匹配参数类型的构造函数");
        }
    }

    private static ObjectActivator<T> GetActivator<T>(ConstructorInfo ctor)
    {
        var paramsInfo = ctor.GetParameters();
        // 定义Lambda的输入参数:object[]类型的参数数组
        var paramExpr = Expression.Parameter(typeof(object[]), "args");
        var argsExpr = new Expression[paramsInfo.Length];

        for (int i = 0; i < paramsInfo.Length; i++)
        {
            // 从参数数组中取出对应位置的元素,并转换为构造函数所需的类型
            var indexExpr = Expression.Constant(i);
            var paramAccessorExpr = Expression.ArrayIndex(paramExpr, indexExpr);
            var paramCastExpr = Expression.Convert(paramAccessorExpr, paramsInfo[i].ParameterType);
            argsExpr[i] = paramCastExpr;
        }

        // 构建调用构造函数的表达式
        var newExpr = Expression.New(ctor, argsExpr);
        // 编译表达式为委托
        var lambda = Expression.Lambda<ObjectActivator<T>>(newExpr, paramExpr);
        return lambda.Compile();
    }
}

关键细节说明

  • 委托定义:ObjectActivator<T>委托用来匹配带可变参数的构造函数调用,让我们可以用统一的方式传递参数并创建实例。
  • 缓存机制:新增的_activatorCache字典用来缓存已编译的委托,避免同一类型、同一参数组合的实例重复编译Lambda,进一步降低开销。
  • Lambda编译核心:GetActivator<T>方法通过Expression API构建调用目标构造函数的表达式,然后编译成委托。这一步只在第一次创建对应类型实例时执行,后续都是直接调用委托。

使用示例

你可以像这样调用这个工具类,替代原来的Activator.CreateInstance:

// 假设有一个类:public class MyClass { public MyClass(string name, int age) { ... } }
MyClass instance = ClassBuilder.CreateInstance<MyClass>(typeof(MyClass), "张三", 25);

这个实现的性能优势在高频调用场景下会非常明显,完全可以替代Activator.CreateInstance的反射调用。

内容的提问来源于stack exchange,提问作者cheikh ndiaye

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.21 03:57:12