c# - 如何创建匿名对象作为 LINQ 表达式
问题描述
我想使用 C# 中的表达式树创建以下 lambda 表达式:
var result = dataList.GroupBy(x => new { x.Prop1, x.Prop2 })
如何将具有两个属性的匿名类型作为 LINQ 表达式 (lambdaExp)?
这是我到目前为止得到的:
IQueryable<GraphData> queryableData = graphDataList.AsQueryable();
ParameterExpression pe = Expression.Parameter(typeof(GraphData), "x");
Expression prop1 = Expression.PropertyOrField(pe, "Prop1");
Expression prop2 = Expression.PropertyOrField(pe, "Prop2");
var lambdaExp = Expression.Lambda<Func<GraphData, object>>( new { prop1, prop2 } , pe); //doesn't compile
MethodCallExpression groupByCallExpression = Expression.Call(
typeof(Queryable),
"GroupBy",
new Type[] { typeof(GraphData), typeof(object) },
queryableData.Expression,
lambdaExp);
IQueryable<GraphData> result = queryableData.Provider.CreateQuery<GraphData>(groupByCallExpression);
解决方案
当您编写 linq 查询和匿名对象时,编译器隐藏了它为您做的许多魔法。特别是对于匿名对象,它还为您创建新类型。除非该类型存在于某处,否则您将需要手动创建该类型并在其位置使用该类型。
您可以作弊,让编译器创建一个具有该类型的对象并保存对该类型的引用。这样,您可以生成必要的表达式来实例化该对象。
需要注意的一点是,为您创建的匿名对象将具有按定义顺序提供参数的构造函数,因此您只需要调用该构造函数。
var keyType = new { Prop1=default(string), Prop2=default(string) }.GetType();
var ctor = keyType.GetConstructor(new Type[] { typeof(string), typeof(string) });
var param = Expression.Parameter(typeof(GraphData), "x");
var keySelector = Expression.Lambda(
Expression.New(ctor,
Expression.PropertyOrField(param, "Prop1"), // corresponds to Prop1
Expression.PropertyOrField(param, "Prop2") // corresponds to Prop2
),
param
); // returns non-generic LambdaExpression
请记住,我们正在处理编译时未知的类型,因此您的键选择器表达式将没有编译时类型。
推荐阅读
- css - How to keep same single columns separately repeated in CSS grid area
- c# - 从 .NET Core 和实体框架中的单个 POST 请求插入多表?
- sql - SQL除以2个不同表的ID数?
- c# - WCF basicHttpBinding 客户端即使在调用 Close() 后也不会关闭套接字连接
- python - 使用 Beautfiul Soup 提取当前投标金额 - 动态更新值
- java - 检查 null 时的惯用 Kotlin
- python - SQL Server 的 ImportDataSource 函数失败
- c# - Sendkeys 不工作,但找到对象,c#
- bash - 如何使用 bash 脚本查找文件中最长的行?
- webpack - 从 scss 创建 css,然后移动到特定文件夹,但不包含在标题中