c# - IQueryable 上的选择器表达式动态
问题描述
我想从一些 lambda 动态生成一个选择器表达式。
我想像这样声明一个 lambda 表达式列表
Expression<Func<MyEntity, object>> select1 = myentity => myentity.Label;
Expression<Func<MyEntity, object>> select2 = myentity => myentity.User.Name;
Expression<Func<MyEntity, object>> select3 = myentity => myentity.Fields.Where(1 == 1).Select(f => f.Code).FirstOrDefault();
假设我有一堂课:
class MyClass
{
public string Label { get; set; }
public string UserName { get; set; }
public string CodeField { get; set; }
}
我想使用声明的表达式动态组合选择器表达式。目标是我想选择要恢复的数据,而不是全部一起。
Expression.Lambda<Func<MyEntity, MyClass>> selectExpression = ??
req.Select(selectExpression).ToList();
我想生成一个选择器表达式来拥有这样的东西
return req.Select(myentity => new MyClass {
Label = myentity.Label,
UserName = myentity.User.Name,
CodeField = myentity.Fields.Where(1 == 1).Select(f => f.Code).FirstOrDefault()
}).ToList();
我可以这样做吗?
例如,我成功了,但这不是我要寻找的方式
var entityT = Expression.Parameter(typeof(MyEntity), "entity");
var propertyA = Expression.Property(entityT, typeof(MyEntity).GetProperty("Label"));
var propertyB = Expression.Property(entityT, typeof(MyEntity).GetProperty("User"));
var propertyC = Expression.Property(propertyB, typeof(UserEntity).GetProperty("Name"));
var binding = Expression.MemberInit(Expression.New(typeof(MyClass)),
new[]
{
Expression.Bind(typeof(MyClass).GetProperty("Label"), propertyA),
Expression.Bind(typeof(MyClass).GetProperty("UserName"), propertyC),
});
var selectExpression = Expression.Lambda<Func<Benef, MyClass>>(binding, entityT);
return req.Select(selectExpression).ToList();
同样的想法,我很想这样做,它编译但不起作用:
var binding = Expression.MemberInit(Expression.New(typeof(T)),
new[]
{
Expression.Bind(typeof(T).GetProperty("Label"), select1.Body),
Expression.Bind(typeof(T).GetProperty("UserName"), select2.Body),
});
我有这个错误:“从范围''引用'MyEntity'类型的变量'myentity',但它没有定义”
谢谢您的回答。
解决方案
基本上,您需要从每个 lambda 中提取表达式并将其与参数 from 连接起来MyClass
。
类似的东西:Expression.Bind(typeof(MyClass).GetParameter("x"), selectX.Body)
。
唯一的难点是 all 都selectX.Body
需要指向同一个参数,所以每个body 的表情都需要调整。
这是示例代码:
class Program
{
static void Main(string[] args)
{
var mapped = entities
.Select(MakeExpression<MyEntity, MyClass>(select1, select2, select3))
.ToList();
}
// Create lambda expression
private static Expression<Func<TEntity, TModel>> MakeExpression<TEntity, TModel>(params Expression<Func<TEntity, object>>[] select)
{
var param = Expression.Parameter(typeof(TEntity));
// Map expressions [select1, ..., selectN] with properties
// For keeping things simple I map nth expression with nth property
// eg. select1 with first property from MyClass
var body = Expression.MemberInit(
Expression.New(typeof(TModel)),
typeof(TModel)
.GetProperties()
.Select((p, i) => Expression.Bind(p, MakeParam(param, select[i])))
.ToArray()
);
return Expression.Lambda<Func<TEntity, TModel>>(body, param);
}
// Replace parameter from given expression with param
// All expressions must have same MyEntity parameter
private static Expression MakeParam<TEntity>(ParameterExpression param, Expression<Func<TEntity, object>> select)
{
Expression body = select.Body;
return new ParamVisitor<TEntity>(param).Visit(body);
}
}
class ParamVisitor<TEntity> : ExpressionVisitor
{
private readonly ParameterExpression _param;
public ParamVisitor(ParameterExpression param)
{
this._param = param;
}
protected override Expression VisitParameter(ParameterExpression node)
{
if (node.Type == typeof(TEntity))
{
return this._param;
}
return base.VisitParameter(node);
}
}
推荐阅读
- java - 为什么我的 IntelliJ 不能导入我的本地类?
- python-3.x - 单击时获取动态创建按钮的 ID
- android - (Android Volley) JSONObject 无法转换为 JSONArray
- python - RuntimeError:模型类未声明显式 app_label 并且不在 INSTALLED_APPS for Django OAuth Toolkit 中的应用程序中
- computer-science - 不表示序列结束的哨兵术语是什么?
- docker - “docker search” 在 bash 中返回的结果比在 hub.docker.com 上少得多
- python-3.x - 如何在非 Sequential() Keras 模型的层中设置权重和梯度权重
- r - 如何在 1 个图中绘制多个数据集的概率密度函数图?
- three.js - A-Frame:0.9.0 和 0.9.2 版本之间的“透视截图”功能中断?
- docker - 无法使用手动 iptables 在 Dockerfile 中运行 apt-get update