Should LINQ lambda expression parameters be reused in a second lambda?

后端 未结 2 2005
独厮守ぢ
独厮守ぢ 2021-01-05 01:08

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

相关标签:
2条回答
  • 2021-01-05 01:28

    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?

    0 讨论(0)
  • 2021-01-05 01:35

    You need to consider your use case. How might these lambdas be combined in the future?

    For example, are you going to want to combine two lambdas using an OR operation?

    Expression<Func<Person, bool>> lambda1 = p => !p.IsDeleted;
    Expression<Func<Person, bool>> lambda2 = p => p.DomainId == 1;
    // How do I get (p => !p.IsDeleted || p.DomainId == 1)?
    

    If so, it's easier to join them like this:

    Expression.Lambda<Func<Person, bool>>(
        Expression.OrElse(lambda1.Body, lambda2.Body), 
        lambda1.Parameters[0]);
    

    The above code works just fine if they both have the same parameter expression object. If they don't, suddenly you have to traverse the entire tree of lambda2, creating a new expression tree that substitutes the parameter for the one that's in the first expression. It can be done, and I've written some utility methods to make it easy when I have to do stuff like this, but if you can identify that this is the type of use case you're going to run into you might as well make life simpler for yourself by using the same parameter in the first place.

    On the other hand, if you're going to combine the lambdas in a way that the parameters need to play different roles in a larger lambda expression, as Eric pointed out, then you're going to need those parameters to be different.

    0 讨论(0)
提交回复
热议问题