System.LINQ.Dynamic:选择("new(...)")到List< T>中. (或< T>的任何其他可枚举的集合) [英] System.LINQ.Dynamic: Select(" new (...)") into a List<T> (or any other enumerable collection of <T>)
问题描述
说我有一个包含四个列的数据表,公司(字符串),基金(字符串),州(字符串),值(双精度):
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构建一个动态查询,该查询按公司,基金或州进行分组,然后按条件选择我的组作为第一列,并求和(值):
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(组)将始终为字符串,并且总和始终为双精度,因此我希望能够转换为类似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:使用反射访问动态对象的Group
和TotalValue
属性.
Option 1: Use reflection to access the dynamic object's Group
and TotalValue
properties.
选项2:使用编译的表达式树进行轻量级代码生成以访问Group
和TotalValue
属性.
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:
-
在
ExpressionParser.Parse()
中,在专用字段中捕获type参数:
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()
的强类型版本:
Finally, we need a strongly typed version of 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:选择("new(...)")到List< T>中. (或< T>的任何其他可枚举的集合)的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!