如何创建表达式实现C#列表单个属性求和?遇参数数量错误
问题:构建Sum表达式时提示“调用Sum方法时提供的参数数量不正确”
尝试为列表属性创建表达式时遇到错误:
错误:调用Sum方法时提供的参数数量不正确
使用的代码如下:
ParameterExpression argParam = Expression.Parameter(typeof(T), "s"); property1 = typeof(T).GetProperty(nameof(Srt)); property2 = property1.PropertyType.GetProperty(Srt.Srtd)); propertyExp1 = Expression.Property(argParam, property1); propertyExp = Expression.Property(propertyExp1, property2); // in propertyExp I got {s.Srt.Srtd} ParameterExpression argX = Expression.Parameter(typeof(Srtd), "x"); var prt1= typeof(Srtd).GetProperty(nameof(Srtd.Elt)); var prtExp= Expression.Property(argX, prt1); // in prtExp I got {x.Elt} var method = typeof(System.Linq.Enumerable).GetMethod("Sum", new[] { typeof(IEnumerable<decimal?>) }); var exp2 = Expression.Call(method, propertyExp, prtExp);
目标是生成类似 {s.Srt.Srtd.Sum(x=>x.Elt)} 的表达式,求解决方法。
解决方案
问题核心在于两点:
- 获取的Sum方法重载不符合需求:你当前获取的是仅接受
IEnumerable<decimal?>的无参数Sum重载,但实际需要的是带selector委托的重载(即Sum<TSource>(this IEnumerable<TSource>, Func<TSource, decimal?>))。 - Expression.Call的参数逻辑错误:未正确构建selector的Lambda表达式,也未匹配扩展方法的调用参数规则。
修正步骤如下:
- 构建selector的Lambda表达式
把x => x.Elt转换成表达式树结构:
ParameterExpression argX = Expression.Parameter(typeof(Srtd), "x"); var prt1 = typeof(Srtd).GetProperty(nameof(Srtd.Elt)); var prtExp = Expression.Property(argX, prt1); // 生成x => x.Elt的Lambda表达式 var selectorLambda = Expression.Lambda<Func<Srtd, decimal?>>(prtExp, argX);
- 获取正确的Sum泛型重载方法
通过筛选找到带两个参数的Sum方法定义,再指定泛型类型:
// 筛选带selector参数的Sum方法定义,再实例化为Srtd类型的泛型方法 var sumMethodDefinition = typeof(System.Linq.Enumerable).GetMethods() .Where(m => m.Name == "Sum" && m.GetParameters().Length == 2) .First() .MakeGenericMethod(typeof(Srtd));
- 生成正确的Sum调用表达式
扩展方法的调用逻辑中,第一个参数是源集合(propertyExp即s.Srt.Srtd),第二个参数是selector的Lambda表达式:
var exp2 = Expression.Call(sumMethodDefinition, propertyExp, selectorLambda);
完整修正代码
ParameterExpression argParam = Expression.Parameter(typeof(T), "s"); var property1 = typeof(T).GetProperty(nameof(Srt)); var property2 = property1.PropertyType.GetProperty(nameof(Srt.Srtd)); // 修正语法:使用nameof获取属性名 var propertyExp1 = Expression.Property(argParam, property1); var propertyExp = Expression.Property(propertyExp1, property2); ParameterExpression argX = Expression.Parameter(typeof(Srtd), "x"); var prt1 = typeof(Srtd).GetProperty(nameof(Srtd.Elt)); var prtExp = Expression.Property(argX, prt1); var selectorLambda = Expression.Lambda<Func<Srtd, decimal?>>(prtExp, argX); var sumMethodDefinition = typeof(System.Linq.Enumerable).GetMethods() .Where(m => m.Name == "Sum" && m.GetParameters().Length == 2) .First() .MakeGenericMethod(typeof(Srtd)); var exp2 = Expression.Call(sumMethodDefinition, propertyExp, selectorLambda);
执行以上代码后,就能生成你需要的s.Srt.Srtd.Sum(x=>x.Elt)表达式树。
内容的提问来源于stack exchange,提问作者Rushi Sharma
相关产品推荐
相关产品推荐

