可以访问表达式树中父表达式的参数。 [英] Get access to a parameter of a parent expression within expression tree.

查看:100
本文介绍了可以访问表达式树中父表达式的参数。的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在使用Entity Framework,需要在运行时动态创建过滤器。

我需要创建一个能够访问父调用参数的表达式,例如:

x => x.Roles.Select(y => y.Actions.Where(z =>!x.IsActive || z.IsActive))



这样这样filter应该为根对象选择_all_ Actions,如果该根对象是_not_ active,或者选择所有_active_ Actions,如果该对象是活动的。



我有代码它创建了这种类型的表达式,但不清楚如何从Where过滤器中访问x参数。

因为Where过滤器由一个单独的表达式表示,它只接受z参数,所以它没有x绑定。





应该怎样做才能在该级别上获得该参数?



谢谢,

Alex



我尝试了什么:



我不能在这里放一个例子代码,因为它不简单,因为它动态计算表达式中的对象类型。

它只是基于常规方法,但通过反射工作。

I'm working with Entity Framework and need to create filters dynamically in run time.
I need to create an expression which should be able to access parameter of a parent call, e.g.:
x => x.Roles.Select(y => y.Actions.Where(z => !x.IsActive || z.IsActive))

so that this filter should select _all_ Actions for a root object, if that root object is _not_ active, or select all _active_ Actions, if that object is active.

I've code which creates an expression of such kind, but it is not clear how to get access to x parameter from within the Where filter.
Since Where filter is represented by a separate expression, which accepts only z parameter, it doesn't have x bound.


What should be done to get that parameter available on that level ?

Thanks,
Alex

What I have tried:

I can't put here an example of the code, because it is not simple, since it dynamically calculates types of objects ivolved into expressions.
It's just based on regular approach but working through reflection.

推荐答案

内部lambda表达式可以访问外部lambda表达式中的参数:

The inner lambda expression will have access to the parameters from the outer lambda expression:
var x = Expression.Parameter(typeof(Widget), "x");
var y = Expression.Parameter(typeof(Role), "y");
var z = Expression.Parameter(typeof(RoleAction), "z");

// z => !x.IsActive || z.IsActive
var roleActionBody = Expression.OrElse(
    Expression.Not(Expression.Property(x, "IsActive")),
    Expression.Property(z, "IsActive"));

// y => y.Actions.Where(z => ...)
var roleBody = Expression.Call(typeof(Enumerable), "Where", new[] { typeof(RoleAction) },
    Expression.Property(y, "Actions"),
    Expression.Lambda(roleActionBody, z));

// x => x.Roles.Select(y => ...)
var body = Expression.Call(typeof(Enumerable), "Select", new[] { typeof(Role), typeof(IEnumerable<RoleAction>) },
    Expression.Property(x, "Roles"),
    Expression.Lambda(roleBody, y));

var result = Expression.Lambda<Func<Widget, IEnumerable<IEnumerable<RoleAction>>>>(body, x);



NB:结果是一系列 RoleAction 对象的序列。如果要将其展平为 RoleAction 对象的序列,则需要使用 SelectMany


NB: The result is a sequence of sequences of RoleAction objects. If you want to flatten that to a sequence of RoleAction objects, you'll need to use SelectMany:

...

// x => x.Roles.SelectMany(y => ...)
var body = Expression.Call(typeof(Enumerable), "SelectMany", new[] { typeof(Role), typeof(RoleAction) },
    Expression.Property(x, "Roles"),
    Expression.Lambda(roleBody, y));

var result = Expression.Lambda<Func<Widget, IEnumerable<RoleAction>>>(body, x);


x在范围内。



"x" is in scope.

class RoleAction {
   public bool IsActive;
}

class Role {
   public List<RoleAction> Actions = new List<RoleAction>();
}

class Widget {
   public List<Role> Roles = new List<Role>();
   public bool IsActive;
}

class Program {
   static void Main( string[] args ) {
      List<Widget> widgets = new List<Widget>();
      var q = widgets.Select( x => x.Roles.Select( y => y.Actions.Where( z => !x.IsActive || z.IsActive ) ) );
   }
}


这篇关于可以访问表达式树中父表达式的参数。的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆