[英]Selector expression dynamic on IQueryable
I would like to generate dynamically a selector expression from some lambdas. 我想从一些lambda动态生成选择器表达式。
I want to declare a list of lambda expression like this 我想声明这样的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();
And let's say i have a class : 假设我有一堂课:
class MyClass
{
public string Label { get; set; }
public string UserName { get; set; }
public string CodeField { get; set; }
}
I want to compose dynamically the selector expression using the declared expressions. 我想使用声明的表达式动态组成选择器表达式。 The goal is that I want to choose the data to recover, not all together.
目的是我要选择要恢复的数据,而不是全部。
Expression.Lambda<Func<MyEntity, MyClass>> selectExpression = ??
req.Select(selectExpression).ToList();
I want to generate a selector expression to have something like this 我想生成一个选择器表达式以具有这样的内容
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();
Can i do this? 我可以这样做吗?
I succeeded for example like this but it's not the way that i'm look for 例如,我成功获得了这样的成功,但这并不是我寻找的方式
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();
In the same idea, I was tempted to do this, it compiles but does'nt work: 在相同的想法中,我很想这样做,它可以编译但不起作用:
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),
});
I have this error : "variable 'myentity' of type 'MyEntity' referenced from scope '', but it is not defined" 我有此错误:“从作用域”引用了类型'MyEntity'的变量'myentity',但未定义”
Thank you for your answers. 谢谢您的回答。
Basically you need to extract expressions from each lambda and connect it with parameter from MyClass
. 基本上,您需要从每个lambda中提取表达式,并将其与
MyClass
参数连接。
Something like: Expression.Bind(typeof(MyClass).GetParameter("x"), selectX.Body)
. 类似于:
Expression.Bind(typeof(MyClass).GetParameter("x"), selectX.Body)
。
The only difficulty is that all selectX.Body
needs to point to the same paramter, so each body expression needs to be adjusted. 唯一的困难是所有
selectX.Body
需要指向相同的参数,因此每个主体表达式都需要调整。
Here is sample code: 这是示例代码:
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);
}
}
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.