-->

System.LINQ.Dynamic:选择(“新的(......)”)到列表 (或者任何其他

2019-07-19 03:37发布

说我有一个四列,公司(串),基金(串),国家(串),值(双)数据表:

    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建立一个动态查询在任公司,基金,或国家,这组,然后通过标准的第一列,和(数值)选择我的组:

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

在上面的查询,选定groupbyvalue(集团)将永远是一个字符串,总和将永远是一个双重的,所以我希望能够投进去的东西就像一个列表,其中结果是地产集团的对象(字符串)及总价值(双)。

我有很多的麻烦这一点,任何人都可以提供一些线索?

Answer 1:

首先,你访问当前分组值作为Key在SELECT子句:

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

这应该使您的查询工作。 更难的问题是如何将返回的对象,这将具有从继承的动态生成的类型DynamicClass ,成静态类型。

方法1:使用反射来访问动态对象的GroupTotalValue属性。

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

方案3:修改动态库,支持强类型的结果。 这原来是很简单的:

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

     private Type newResultType; public Expression Parse(Type resultType) { newResultType = resultType; int exprPos = token.pos; // ... 
  2. 临近年底ExpressionParser.ParseNew()我们将尝试使用newResultType默认为动态类型之前:

     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); } 
  3. 最后,我们需要的强类型版本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

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

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

而更新后的查询将是这样的:

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


Answer 2:

我铸造通过以下方式返回的数据列表<IExampleInterface>:

1扩展动态LINQ的选择方法来支持泛型类型。 见第一个答案在这里

2使用选择方法(非常类似于dahlbyk的答案的第一行)

Select<dynamic>("new (Key as Group, Sum(Value) as TotalValue)")

如果您需要多列,您可以使用下列内容:

GroupBy(@"new (Fund, Column1, Column2)", "it").
Select<dynamic>("new (Key.Fund, Key.Column1, Key.Column2, Sum(Value) as TotalValue)")

3转换数据列出。

var data = ...
  GroupBy("...").Select<dynamic>("...").
  Cast<dynamic>().AsEnumerable().ToList();

4使用即兴到列表转换为列表<IExampleInterface>

var result = new List<IExampleInterface>();

foreach (var d in data)
{
  dynamic r = Impromptu.ActLike<IExampleInterface>(d);
  result.Add(r);
}


Answer 3:

另一种可能性是延长的DLinq的查询语言与可能性,在指定类型名new查询字符串中的条款。

我所描述的变化的Dynamic.cs需要在另一计算器的答案 。

它可以让你提出类似下面的查询:

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


Answer 4:

另外,更容易的方式做到这一点是使用Newtonsoft.Json像这样使用JSON序列化/反序列化:

具有与希望属性的类:

public class MyClass
{
    public string Group;

    public double Total;
}

查询后,你的JSON序列化,然后反序列化到你想要的数据类型:

string jsonData = JsonConvert.SerializeObject(q1);
List<MyClass> typedResult = JsonConvert.DeserializeObject<List<MyClass>>(jsonData);


文章来源: System.LINQ.Dynamic: Select(“ new (…)”) into a List (or any other enumerable collection of )