如何在ExpressionParameter中处理装箱拆箱实现方法通用包装
解决方案
你遇到的报错核心原因是Expression.NewArrayInit构造object[]数组时,要求所有传入的元素表达式必须和数组元素类型object兼容,值类型默认不会做隐式装箱,因此需要手动给每个参数表达式添加转换逻辑。
仅需修改BuildWrappedDomainMethod方法中构造参数数组的一行代码即可:
// 原代码 // var parametersArrayNewExpression = Expression.NewArrayInit(typeof(object), parametersList); // 修改为下面的代码,给每个参数加显式转object的逻辑,自动实现值类型装箱 var parametersArrayNewExpression = Expression.NewArrayInit(typeof(object), parametersList.Select(p => Expression.Convert(p, typeof(object))));
逻辑说明
Expression.Convert(p, typeof(object))会自动适配不同参数类型:
- 对于值类型参数,生成装箱操作,把int等值类型转为object
- 对于引用类型参数,生成安全的引用转换操作,无额外性能开销
修改后完整的BuildWrappedDomainMethod代码如下:
public Delegate BuildWrappedDomainMethod(Delegate domainMethod, string message) { var thisInstanceExpression = Expression.Constant(this); var wrappingMethodInfo = GetMethodInfo<ExpressionUnderstandingFixture>(f => f.WrappingMethod(null, null, null)); var messageExpression = Expression.Constant(message); var domainMethodExpression = Expression.Constant(domainMethod); var parametersList = domainMethod.Method.GetParameters().Select(pi => Expression.Parameter(pi.ParameterType)).ToList(); // 仅修改下面这一行 var parametersArrayNewExpression = Expression.NewArrayInit(typeof(object), parametersList.Select(p => Expression.Convert(p, typeof(object)))); var wrappedMethodCallExpression = Expression.Call( thisInstanceExpression, wrappingMethodInfo, messageExpression, domainMethodExpression, parametersArrayNewExpression); var wrappedMethodCallLambdaExpression = Expression.Lambda( domainMethod.GetType(), wrappedMethodCallExpression, parametersList); var wrapedCallLambda = wrappedMethodCallLambdaExpression.Compile(); return wrapedCallLambda; }
修改完成后两个测试用例均可正常运行,兼容引用类型和值类型的参数场景。
内容的提问来源于stack exchange,提问作者Rico-E
相关产品推荐
相关产品推荐

