1

I'm trying to work out the syntax for using an anonymous function inside the lambda of a linq .Where() call.

I'm using the Where to filter certain items from a list.

I want each part of the filter logic inside the Where. The logic is only useful inside the filter so I don't want to have to define any functions outside.

Here's a simplified & generalised example:

var filtered = myEnumerable.Where(item =>
    item.PropertyA == 1 ||
    item.PropertyB == 2 ||
    item => 
    {
        var heavyResult = GetStuff(item); // Some heavyweight processing
        return heavyResult.IsSomethingTrue() && heavyResult.IsSomethingElseTrue();
    });

So I want the third line in the Where() to be an anonymous function taking item and returning a boolean.

Also, the function being called after the checks on PropertyA and PropertyB is intended to limit having to call GetStuff() if either of those lightweight comparisons already evaluated as true.

I can't do it all inline because I need to evaluate two properties from heavyResult.

This seems like it should be simple, but I don't seem to be able to find the right syntax, either by experimenting or Googling.

2
  • I am actually skeptical whether this is real scenario? You can do it in simpler numerous ways Commented Aug 3, 2017 at 10:34
  • While you could do this I doubt you should, as it just adds the need to document what exactly the function does. Instead just extract a named method that has an descriptive name to identify what happens within that method. Commented Aug 3, 2017 at 10:38

2 Answers 2

2

I can't do it all inline because I need to evaluate two properties from heavyResult.

You can do it inline, its just you need to wrap the entire thing in {} and use the return keyword.

var filtered = myEnumerable.Where(item =>
    {
        var test = item.PropertyA == 1 || item.PropertyB == 2;
        if(test)
          return true; 
        var heavyResult = GetStuff(item); // Some heavyweight processing
        return heavyResult.IsSomethingTrue() && heavyResult.IsSomethingElseTrue();
    });

To be honest though - doing something that even that simple inline is probably the wrong choice. Extract it into a function, with a meaningful name, and your code is self documenting

var filtered = myEnumerable.Where(ADescriptiveNamedFunctionSelfDocumentsYourCode);
Sign up to request clarification or add additional context in comments.

3 Comments

Thanks. I did get it working with this style. It just looks uglier to me for the PropertyA and PropertyB checks. It seems there should be a way to bundle the GetStuff/heavyResult part into an anonymous function.
@Tom - there is. Its in this answer.
Thanks all. I appreciate the comments regarding should I try to do it that way, and I think in my real example I will have to define an external method to do the filtering logic. In terms of my specific question above, and purely syntactically speaking, I guess the answer is - no, there is not a way to define an anonymous function inline like that?
0

Firstly, multiline lambdas are a really bad idea.

They were intended as simple functional representations f(x)= ... stuff.

You can't do this the way you're thinking because you first want to call a function, capture its result, & then call 2 different methods on that object.

You can do this more simply by moving the delegate out of the lambda.

The latest version of C# supports local functions, which may be what you want. But you can still do this with anonymous functions in C# 6.

I've also shown how you can do this with another method in HeavyResult or an extension method it's not feasible to change HeavyResult.

In the code below, you would use only one of the options from

validator(item) ||
GetStuff(item).IsAllTrue() ||
GetStuff(item).IsAllTrueExt()

Here's the full code:

public static class Program
{
    static void Main(string[] args)
    {
        var myEnumerable = new List<int>() { 1, 2, 3, 4, 5 };

        Predicate<int> validator;
        validator = delegate (int item)
        {
            var heavyResult = GetStuff(item);
            return heavyResult.IsSomethingTrue() && heavyResult.IsSomethingElseTrue();
        };

        var filtered = myEnumerable.Where(item =>
        item >= 1 ||
        item <= 200 ||
        validator(item) ||
        GetStuff(item).IsAllTrue() ||
        GetStuff(item).IsAllTrueExt()
        );
    }

    public static bool IsAllTrueExt(this HeavyResult hr)
    {
        { return hr.IsSomethingTrue() && hr.IsSomethingElseTrue(); }
    }

    public static HeavyResult GetStuff(int item)
    {
        return new HeavyResult(item);
    }

    public class HeavyResult
    {
        public HeavyResult(int value)
        {
            Value = value;
        }

        int Value { get; }

        public bool IsSomethingTrue()
        {
            { return Value >= 5; }
        }

        public bool IsSomethingElseTrue()
        {
            { return Value <= 50; }
        }

        public bool IsAllTrue()
        {
            { return IsSomethingTrue() && IsSomethingElseTrue(); }
        }

    }
}

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.