如何通过表达式创建支持可变参数构造函数的Func<Type,object[],object>?
用Expression实现支持可变参数构造的实例创建器
要实现你需要的Creator方法,核心是为每个目标Type预编译适配其构造函数的委托并缓存——直接每次调用都生成表达式会抵消性能优势,缓存是关键。下面是具体实现:
核心实现代码
using System; using System.Collections.Concurrent; using System.Linq; using System.Linq.Expressions; public static class InstanceCreator { // 线程安全的缓存:存储Type到对应构造委托的映射 private static readonly ConcurrentDictionary<Type, Func<object[], object>> _constructorCache = new(); public static object Creator(Type targetType, object[] parameters) { // 从缓存获取委托,不存在则动态创建并缓存 var constructor = _constructorCache.GetOrAdd(targetType, type => { // 优先匹配参数实际类型的构造函数,适配重载场景 var ctor = type.GetConstructor(parameters.Select(p => p.GetType()).ToArray()) // fallback:尝试匹配object类型参数的构造函数(应对隐式转换) ?? type.GetConstructor(parameters.Select(_ => typeof(object)).ToArray()) ?? throw new InvalidOperationException($"找不到匹配的构造函数:{type.FullName}"); // 定义委托的输入参数:object[]类型的参数数组 var paramExpr = Expression.Parameter(typeof(object[]), "args"); // 构造每个构造参数的表达式:从数组取元素并转换为目标类型 var argExprs = ctor.GetParameters() .Select((param, index) => Expression.Convert( Expression.ArrayIndex(paramExpr, Expression.Constant(index)), param.ParameterType)); // 生成调用构造函数的表达式 var newExpr = Expression.New(ctor, argExprs); // 编译为可直接调用的委托 return Expression.Lambda<Func<object[], object>>(newExpr, paramExpr).Compile(); }); return constructor(parameters); } }
关键细节说明
- 缓存机制:用
ConcurrentDictionary保证多线程下的安全,避免重复编译同一个Type的构造逻辑,最大化性能优势。 - 构造函数匹配:先尝试匹配参数实际类型的构造函数,适配重载场景;如果找不到,再尝试匹配参数为
object类型的构造函数,覆盖隐式转换的情况。 - 参数类型转换:通过
Expression.Convert自动处理object数组元素到构造参数类型的转换,解决类型不匹配问题。
使用示例
// 测试类定义 public class ClassA { public ClassA(int a, int b) { Console.WriteLine($"ClassA实例化:a={a}, b={b}"); } } public class ClassB { public ClassB(string text) { Console.WriteLine($"ClassB实例化:text={text}"); } } // 调用方式完全符合需求 var a = InstanceCreator.Creator(typeof(ClassA), new object[] { 1, 2 }); var b = InstanceCreator.Creator(typeof(ClassB), new object[] { "some text" });
性能表现
编译后的委托性能接近直接new Class()的原生调用,远优于Activator.CreateInstance,且缓存机制避免了重复编译的开销,适合高频调用场景。
内容的提问来源于stack exchange,提问作者Andre Wessel
相关产品推荐
相关产品推荐

