c#linq methodcallexpression用于.groupedby().选择().[英] c# linq MethodCallExpression for Max(DataRow) used for .GroupedBy().Select()

本文是小编为大家收集整理的关于c#linq methodcallexpression用于.groupedby().选择().的处理/解决方法,可以参考本文帮助大家快速定位并解决问题,中文翻译不准确的可切换到English标签页查看源文。

问题描述

这个问题在此指的是我以前的问题在这里 @xanatos建议的sum()表达式完美. 我还尝试了double类型字段的max()表达式,并且没有问题.
作为下一步,我决定添加DateTime字段并为其计算Max().
我修改了组类,如下:

private class GroupSum : GroupKey
{
    public Double AggN0 { get; set; }
    public DateTime AggD0 { get; set; }
}

并编程了功能:

private static Func<IGrouping<GroupKey, DataRow>, DateTime> GetFuncMaxDateTime()
{
    MethodInfo methInfo = typeof(DataRowExtensions).GetMethod("Field", new Type[] { typeof(DataRow), typeof(string) });

    ParameterExpression expRow = Expression.Parameter(typeof(DataRow), "row");  //Parametr: (row =>....)

    PropertyInfo propertyInfo = typeof(GroupSum).GetProperty("AggD0");

    MethodCallExpression expCall = GetFieldCallExpression(expRow, methInfo, propertyInfo.PropertyType, "DocumentDate");

    var expRowValues = Expression.Lambda(expCall, expRow);

    ParameterExpression expQuerygroup = Expression.Parameter(typeof(IGrouping<GroupKey, DataRow>), "g");

    //HERE it throws an error: No generic method 'Max' on type 'System.Linq.Enumerable' is compatible with the supplied type arguments and arguments. No type arguments should be provided if the method is non-generic. 
    MethodCallExpression expMaxRows = Expression.Call(typeof(Enumerable), "Max", new[] { expRow.Type }, expQuerygroup, expRowValues);

    var max = Expression.Lambda<Func<IGrouping<GroupKey, DataRow>, DateTime>>(expMaxRows, expQuerygroup);
    return max.Compile();
}

代码编译,但在运行时会引发错误.我评论了该说明并指定了错误消息. 这很奇怪,因为唯一的区别是
double sum(double)
vs
DateTime Max(DateTime)

无需添加硬编码版本正常.

private static IEnumerable<GroupSum> GetListOfGroupedRows(IEnumerable<IGrouping<GroupKey, DataRow>> queryGroup)
{
    IEnumerable<GroupSum> querySelect = queryGroup
        .Select(g => new GroupSum
        {
            KeyS0 = g.Key.KeyS0,
            KeyS1 = g.Key.KeyS1,
            AggN0 = g.Sum(row => row.Field<double>("Amount")),
            AggD0 = g.Max(row => row.Field<DateTime>("DocumentNumber"))
        });
    return querySelect;
}

推荐答案

更改此行添加expRowValues.ReturnType:

MethodCallExpression expMaxRows = Expression.Call(
    typeof(Enumerable), 
    nameof(Enumerable.Max), 
    new[] { expRow.Type, expRowValues.ReturnType }, 
    expQuerygroup, 
    expRowValues);

因为您想要这个过载:

public static TResult Max<TSource, TResult>(this IEnumerable<TSource> source, Func<TSource, TResult> selector);

so 两个通用类型参数

本文地址:https://www.itbaoku.cn/post/1556997.html

问题描述

The question hereby refers to my previous question here The Sum() expression advised by @xanatos worked perfectly. I tried also Max() expression for the field of the type double and faced no issue.
As the next step I decided to add the DateTime field and calculate Max() for it.
I modified the GroupSum class as follows:

private class GroupSum : GroupKey
{
    public Double AggN0 { get; set; }
    public DateTime AggD0 { get; set; }
}

And programmed the function:

private static Func<IGrouping<GroupKey, DataRow>, DateTime> GetFuncMaxDateTime()
{
    MethodInfo methInfo = typeof(DataRowExtensions).GetMethod("Field", new Type[] { typeof(DataRow), typeof(string) });

    ParameterExpression expRow = Expression.Parameter(typeof(DataRow), "row");  //Parametr: (row =>....)

    PropertyInfo propertyInfo = typeof(GroupSum).GetProperty("AggD0");

    MethodCallExpression expCall = GetFieldCallExpression(expRow, methInfo, propertyInfo.PropertyType, "DocumentDate");

    var expRowValues = Expression.Lambda(expCall, expRow);

    ParameterExpression expQuerygroup = Expression.Parameter(typeof(IGrouping<GroupKey, DataRow>), "g");

    //HERE it throws an error: No generic method 'Max' on type 'System.Linq.Enumerable' is compatible with the supplied type arguments and arguments. No type arguments should be provided if the method is non-generic. 
    MethodCallExpression expMaxRows = Expression.Call(typeof(Enumerable), "Max", new[] { expRow.Type }, expQuerygroup, expRowValues);

    var max = Expression.Lambda<Func<IGrouping<GroupKey, DataRow>, DateTime>>(expMaxRows, expQuerygroup);
    return max.Compile();
}

The code compiles but it throws an error at runtime. I commented the instruction and specified the error message. It is strange because the only difference is
double Sum(double)
vs
DateTime Max(DateTime)

No need to add that hardcoded version works ok.

private static IEnumerable<GroupSum> GetListOfGroupedRows(IEnumerable<IGrouping<GroupKey, DataRow>> queryGroup)
{
    IEnumerable<GroupSum> querySelect = queryGroup
        .Select(g => new GroupSum
        {
            KeyS0 = g.Key.KeyS0,
            KeyS1 = g.Key.KeyS1,
            AggN0 = g.Sum(row => row.Field<double>("Amount")),
            AggD0 = g.Max(row => row.Field<DateTime>("DocumentNumber"))
        });
    return querySelect;
}

推荐答案

Change this line adding expRowValues.ReturnType:

MethodCallExpression expMaxRows = Expression.Call(
    typeof(Enumerable), 
    nameof(Enumerable.Max), 
    new[] { expRow.Type, expRowValues.ReturnType }, 
    expQuerygroup, 
    expRowValues);

because you want this overload:

public static TResult Max<TSource, TResult>(this IEnumerable<TSource> source, Func<TSource, TResult> selector);

so two generic type parameters!