System.LINQ.Dynamic: Select(“new (...)") into a List<T>(或任何其他可枚举的 &lt;T&gt; 集合) [英] System.LINQ.Dynamic: Select(&quot; new (...)&quot;) into a List&lt;T&gt; (or any other enumerable collection of &lt;T&gt;)

查看:20
本文介绍了System.LINQ.Dynamic: Select(“new (...)") into a List<T>(或任何其他可枚举的 &lt;T&gt; 集合)的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

假设我有一个包含四列的 DataTable,Company(字符串)、Fund(字符串)、State(字符串)、Value(double):

Say I have a DataTable with four columns, Company (string), Fund (string), State (string), Value(double):

    table1.Rows.Add("Company 1","Fund 1","NY",100));
    table1.Rows.Add("Company 2","Fund 1","CA",200));
    table1.Rows.Add("Company 3","Fund 1","FL",300));
    table1.Rows.Add("Company 4","Fund 2","CA",400));
    table1.Rows.Add("Company 5","Fund 1","NY",500));
    table1.Rows.Add("Company 6","Fund 2","CA",600));
    table1.Rows.Add("Company 7","Fund 3","FL",700));

我想使用 System.LINQ.Dynamic 来构建一个动态查询,该查询对 Company、Fund 或 State 进行分组,然后按条件选择我的组作为第一列和 sum(value):

I want to use System.LINQ.Dynamic to build a dynamic query which groups on either Company, Fund, or State, and then selects my group by criteria as the first column, and sum(value):

string groupbyvalue="Fund";
var q1= table1.AsEnumerable().AsQueryable()
              .GroupBy(groupbyvalue,"it")
              .Select("new ("+groupbyvalue+" as Group, Sum(Value) as TotalValue)");

在上面的查询中,选中的groupbyvalue(Group)将始终是一个字符串,并且总和将始终是一个double,所以我希望能够转换成一个类似List的东西,其中Result是一个有属性的对象组(字符串)和 TotalValue(双).

In the above query, the selected groupbyvalue (Group) will always be a string, and the sum will always be a double, so I want to be able to cast into something like a List, where Result is an object with properties Group (string) and TotalValue (double).

我在这方面遇到了很多麻烦,有人能解释一下吗?

I'm having a lot of trouble with this, can anyone shed some light?

推荐答案

首先,您将在 Select 子句中以 Key 的形式访问当前分组的值:

First, you'll access the current grouped value as Key in your Select clause:

.Select("new (Key as Group, Sum(Value) as TotalValue)");

这应该使您的查询有效.更难的问题是如何将返回的对象(具有从 DynamicClass 继承的动态生成的类型)转换为静态类型.

That should make your query work. The harder question is how to turn the returned objects, which will have a dynamically generated type that inherits from DynamicClass, into a static type.

选项 1:使用反射访问动态对象的 GroupTotalValue 属性.

Option 1: Use reflection to access the dynamic object's Group and TotalValue properties.

选项 2:使用已编译的表达式树生成轻量级代码以访问 GroupTotalValue 属性.

Option 2: Use compiled expression trees for lightweight code generation to access the Group and TotalValue properties.

选项 3:修改动态库以支持强类型结果.事实证明这相当简单:

Option 3: Modify the Dynamic library to support a strongly-typed result. This turns out to be rather simple:

  1. ExpressionParser.Parse()中,捕获私有字段中的类型参数:

  1. In ExpressionParser.Parse(), capture the type argument in a private field:

private Type newResultType;
public Expression Parse(Type resultType)
{
    newResultType = resultType;
    int exprPos = token.pos;
    // ...

  • 接近 ExpressionParser.ParseNew() 的结尾,我们将尝试在默认为动态类型之前使用 newResultType:

  • Near the end of ExpressionParser.ParseNew(), we'll try to use newResultType before defaulting to a dynamic type:

    Expression ParseNew()
    {
        // ...
        NextToken();
        Type type = newResultType ?? DynamicExpression.CreateClass(properties);
        MemberBinding[] bindings = new MemberBinding[properties.Count];
        for (int i = 0; i < bindings.Length; i++)
            bindings[i] = Expression.Bind(type.GetProperty(properties[i].Name), expressions[i]);
        return Expression.MemberInit(Expression.New(type), bindings);
    }
    

  • 最后,我们需要一个Select()的强类型版本:

    public static IQueryable<TResult> Select<TResult>(this IQueryable source, string selector, params object[] values)
    {
        if (source == null) throw new ArgumentNullException("source");
        if (selector == null) throw new ArgumentNullException("selector");
        LambdaExpression lambda = DynamicExpression.ParseLambda(source.ElementType, typeof(TResult), selector, values);
        return source.Provider.CreateQuery<TResult>(
            Expression.Call(
                typeof(Queryable), "Select",
                new Type[] { source.ElementType, typeof(TResult) },
                source.Expression, Expression.Quote(lambda)));
    }
    

    与原始 Select() 的唯一变化是我们引用 TResult 的地方.

    The only changes from the original Select() are places we reference TResult.

    现在我们只需要一个命名类型来返回:

    Now we just need a named type to return:

        public class Result
        {
            public string Group { get; set; }
            public double TotalValue { get; set; }
        }
    

    您更新后的查询将如下所示:

    And your updated query will look like this:

        IQueryable<Result> res = table1.AsQueryable()
            .GroupBy(groupbyvalue, "it")
            .Select<Result>("new (Key as Group, Sum(Value) as TotalValue)");
    

    这篇关于System.LINQ.Dynamic: Select(“new (...)") into a List<T>(或任何其他可枚举的 &lt;T&gt; 集合)的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

  • 查看全文
    相关文章
    登录 关闭
    扫码关注1秒登录
    发送“验证码”获取 | 15天全站免登陆