代码之家  ›  专栏  ›  技术社区  ›  user2711610

通过表达式调用Enumerable Average

  •  4
  • user2711610  · 技术社区  · 10 年前

    我正在尝试编写动态代码,进行一些聚合Average、Sum、Max等。

    这是我正在执行的代码:

    PropertyInfo sortProperty = typeof(T).GetProperty("PropertyName");
    
    ParameterExpression parameter = Expression.Parameter(typeof(T), "p");
    
    
    MemberExpression propertyAccess = Expression.MakeMemberAccess(parameter, sortProperty);
    LambdaExpression orderByExp = Expression.Lambda(propertyAccess, parameter);
    
    var exp = Expression.Lambda<Func<T, int>>(propertyAccess, parameter);
    
    var call = Expression.Call(typeof(Enumerable), "Average", new[] { typeof(IEnumerable<T>) , typeof(Func<T, int>) }, parameter);
    

    我总是有例外:

    类型“System.Linq.Enumerable”上的泛型方法“Average”与提供的类型参数和参数不兼容。如果方法是非泛型的,则不应提供类型参数。

    1 回复  |  直到 10 年前
        1
  •  3
  •   sloth JohnnBlade    10 年前

    让我们看看这条线。给你打电话 Call

    var call = Expression.Call(typeof(Enumerable), "Average", new[] { typeof(IEnumerable<T>) , typeof(Func<T, int>) }, parameter);
    

    第三个参数是 “指定泛型方法的类型参数的Type对象数组。” 。你正在传递类型 IEnumerable<T> Func<T, int> 但是 Average takes only a single type parameter ( TSource ) .

    第四个参数是 “表示方法参数的Expression对象数组。” 。您正在传递一个表示 T 但是 平均的 需要一个 IEnumerable<TSource> 和一个 Func<TSource, decimal> (或您想调用的任何重载,我只需使用 decimal 一个作为示例)。

    我不知道你使用这段代码的最终目的是什么,但它可能看起来像:

    PropertyInfo sortProperty = typeof(T).GetProperty("Prop");
    ParameterExpression parameter = Expression.Parameter(typeof(T), "p");
    MemberExpression propertyAccess = Expression.MakeMemberAccess(parameter, sortProperty);
    
    // parameter for the source collection
    ParameterExpression source = Expression.Parameter(typeof(IEnumerable<T>), "source");
    
    var exp = Expression.Lambda<Func<T, decimal>>(propertyAccess, parameter);
    var call = Expression.Call(typeof(Enumerable), "Average", new[] {typeof(T)}, source, exp);
    

    下面是一个使用此代码的小示例(您会明白的):

    // assuming a class called T with a decimal property called Prop 
    // because I'm a lazy and terrible person
    var method = Expression.Lambda<Func<IEnumerable<T>, decimal>>(call, source).Compile();
    var result = method(new List<T> {new T { Prop=10}, new T { Prop=20}});
    // result is now 15