Search code examples
c#linqpredicates

Predicate inside a Where<> query not hit?


I need to call the method for each item in the list. So, I have used Where<> query as follows,

List<string> list = new List<string>();
list.Add("Name1");
list.Add("Name2");
list.Add("Name3");

var name = list.Where(n =>
{
    return CheckName(n);
});

But in the above case, CheckName() is not hit. The same method is triggered if I use FirstOrDefault<>. I don't know whether it is a framework break or I am going in a wrong way.

As additional info, I am using.NET Framework 4.5.

Has anyone experienced this error? If so, is there any solution to overcome this issue?


Solution

  • You are understanding incorrectly the result of the Where condition. As linq is deffered executed it will only enter the where condition when materialized (by a ToList/FirstOrDefault/Sum and such).

    The Where is never actually materialized in your current code (It did as you experienced when using FirstOrDefault) and as such it will never enter the CheckName method. Then, as Where will never return null but "worst case" an empty collection, which is not null, the result is true.

    If you debug you will see that name equals true at the end of this. To "overcome" this depends on what is your desired output:

    1. If you want to know if you have any item that matched the predicate then:

      var result = list.Any(CheckName);
      
    2. If you want to retrieve those that match the predicate:

      var result = list.Where(CheckName);
      

      If later you want to query and check if results contains anything then:

      if(result.Any()) { /* ... */ }
      

      If you only want the results (and thus materializing the query):

      list.Where(CheckName).ToList();
      

    Read more about linq being deffered executed here:


    Just as a side note see how you can change your current code from:

    var name = list.Where(n =>
    {
        return CheckName(n);
    })
    

    To:

    var name = list.Where(n => CheckName(n));
    

    And eventually to:

    var name = list.Where(CheckName);