LINQ lambda表达式参数是否应在第二个lambda中重用? [英] Should LINQ lambda expression parameters be reused in a second lambda?

查看:91
本文介绍了LINQ lambda表达式参数是否应在第二个lambda中重用?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

下面是这个问题我想知道是否可以重用的lambda参数表达式实例应该被认为是好是坏?

有时我会得到一完整的LINQ表达式树,其中同一lambda参数实例在第二个非嵌套lambda中正确使用了:

// class Person { public int AProp { get; set; } public bool BProp { get; set; }}
var lparam = Expression.Parameter(typeof(Person),"x");
var lambda1 = (Expression<Func<Person,int>>)Expression.Lambda(Expression.Property(lparam, "AProp"), lparam);
var lambda2 = (Expression<Func<Person,bool>>)Expression.Lambda(Expression.Property(lparam, "BProp"), lparam);
var source = (new Person[0]).AsQueryable();
var query = source.Where(lambda2).OrderBy(lambda1); 

因此,相同的lambda参数实例lparam的声明对于lambda1和lambda2都是正确的.

这只是共享的lambda参数实例强制IQueryProvider实现不基于纯lambda参数引用而关联其他全局含义,因为在处理不同的lambda期间可能需要以不同的方式解释同一参数.另外,您不会通过使用

从LINQ中获得这种表达树(或者我应该说图?)

Expression<Func<Person,int>> lambda3 = x => x.AProp;
Expression<Func<Person,bool>> lambda4 = x => x.BProp;

因为两个lambda表达式都有(Person x)的不同参数实例.

var query = source.Where(x => x.BProp).OrderBy(x => x.AProp);

var query = from x in source where x.BProp order by x.AProp select x;

这也使表达式树更像一个图.

这种重用参数实例的样式被认为是好事还是坏事?到目前为止,我还没有找到当局的明确答案.

解决方案

我不会在两个不相交的lambda之间共享参数对象.

首先,我们不要在这里造假.物体很便宜,而您将不会制造出十万个物体. (如果是的话,您可能还有更大的问题要解决.)

第二点,如您所注意到的,在不相关的lambda上共享参照相同的参数对象,这意味着需要使用分析那些lambda表达式树的代码来理解参数对象在不同上下文中的含义不同.这似乎是一个等待发生的错误.

第三,有人想像某天您可能想要采用两棵表达树:

x => Foo(x);
y => Bar(y);

然后从他们那里得到第三个,说:

(x,y) => Foo(x) && Bar(y);

如果x和y实际上都是相同的参数对象,那么您手头就有问题:

(x,x) => Foo(x) && Bar(x);  // Huh?

另一方面,StriplingWarrior的答案指出,如果您有

x => Foo(x);
x => Bar(x);

然后将它们组合为

会更容易

x => Foo(x) && Bar(x);

因为那样您不需要不需要重写任何内容.

从根本上讲,这似乎是一个冒险的举动,没有真正令人信服的上涨空间,那为什么呢?

Following this question I would like to know if the reuse of lambda parameter expression instances should be considered good or bad?

I sometimes get a complete LINQ expression tree where the same lambda parameter instance is local correctly used in a second, nonnested lambda:

// class Person { public int AProp { get; set; } public bool BProp { get; set; }}
var lparam = Expression.Parameter(typeof(Person),"x");
var lambda1 = (Expression<Func<Person,int>>)Expression.Lambda(Expression.Property(lparam, "AProp"), lparam);
var lambda2 = (Expression<Func<Person,bool>>)Expression.Lambda(Expression.Property(lparam, "BProp"), lparam);
var source = (new Person[0]).AsQueryable();
var query = source.Where(lambda2).OrderBy(lambda1); 

So the declaration of the same lambda parameter instance lparam is correct for both lambda1 and lambda2.

It is just that this shared lambda parameter instance forces IQueryProvider implementations to not associate additional global meaning based on the pure lambda parameter reference, as the same parameter could need to be interpreted differently during processing of a different lambda. Also, you will not get this kind of expression tree (or should I say graph?) from LINQ by using

Expression<Func<Person,int>> lambda3 = x => x.AProp;
Expression<Func<Person,bool>> lambda4 = x => x.BProp;

because there will be different parameter instances of (Person x) for both lambda expressions. The same goes for

var query = source.Where(x => x.BProp).OrderBy(x => x.AProp);

or

var query = from x in source where x.BProp order by x.AProp select x;

It also makes the expression tree to be rather a graph.

Is that style of reuse of parameter instances considered good or bad? So far, I have not found a clear answer to this from the authorities.

解决方案

I would not share a parameter object between two disjoint lambdas.

First, let's not make false economies here. Objects are cheap and you are not going to be making a hundred thousand of these. (And if you are, you probably have larger problems to solve.)

Second, as you note, sharing referentially identical parameter objects across unrelated lambdas means that code which analyzes those lambda expression trees is required to understand that the parameter object has a different meaning in different contexts. That seems like a bug waiting to happen.

Third, one imagines that someday you might want to take two expression trees:

x => Foo(x);
y => Bar(y);

and from them build a third, say:

(x,y) => Foo(x) && Bar(y);

If x and y are actually both the same parameter object then you have a problem on your hands:

(x,x) => Foo(x) && Bar(x);  // Huh?

On the other side, StriplingWarrior's answer points out that if you have

x => Foo(x);
x => Bar(x);

then it is easier to combine them as

x => Foo(x) && Bar(x);

because then you do not need to rewrite anything.

Basically, it just seems like a risky move with no truly compelling upside, so why do it?

这篇关于LINQ lambda表达式参数是否应在第二个lambda中重用?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

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