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>)Expression.Lambda(Expression.Property(lparam, "AProp"), lparam); var lambda2 = (Expression<Func>)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> lambda3 = x => x.AProp; Expression<Func> 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);
因为那时你不需要重写任何东西。
基本上,这似乎是一个冒险的举措,没有真正令人信服的上行空间,为什么呢?
您需要考虑您的用例。 这些lambdas将来如何结合起来呢?
例如,您是否想要使用OR运算组合两个lambda?
Expression> lambda1 = p => !p.IsDeleted; Expression> lambda2 = p => p.DomainId == 1; // How do I get (p => !p.IsDeleted || p.DomainId == 1)?
如果是这样,就像这样加入它们更容易:
Expression.Lambda>( Expression.OrElse(lambda1.Body, lambda2.Body), lambda1.Parameters[0]);
如果它们都具有相同的参数表达式对象,则上述代码可以正常工作。 如果他们不这样做,突然你必须遍历lambda2
的整个树,创建一个新的表达式树,用于替换第一个表达式中的参数。 它可以完成,并且我已经编写了一些实用程序方法,以便在我必须执行此类操作时轻松实现,但是如果您能够确定这是用例的类型,那么您可能会遇到首先使用相同的参数让自己的生活变得更简单。
另一方面,如果你要以一种参数需要在一个更大的lambda表达式中扮演不同角色的方式组合lambdas,正如Eric指出的那样,那么你将需要那些参数不同。