vendredi 8 août 2014

c# - différence entre en comparant les deux propriétés et deux valeurs dans Linq Where clause - Stack Overflow


Please consider the following statement:


var matches = person.Contacts.Where(c => c.ContactType == searchContact.ContactType).ToList();

This will filter all the records with matching ContactType of searchContact object and returns only the filtered Contacts of person. But without ToList() method call at the end of the Where clause, it will return all the Contacts of person.


Now, consider the following code segment.


Dictionary<int, string> colors = new Dictionary<int, string>(){ {1, "red"}, {2, "blue"}, {3, "green"}, {4, "yellow"}, {5, "red"}, {6, "blue"}, {7, "red"} };
var colorSet = colors.Where(c => c.Value == "red");

This query will filter only the elements with value "red", even without calling ToList() method.


My question is why this two statements (one that compares values and one that compares properties) behave in a different way without ToList() method call? Why this problem does not occur with FirstOrDefault instead of Where clause?


I really appreciate, if anyone can explain the scenario or post some references that I can follow. Thanks!!




You are mistaken. Without calling ToList() or another method to force immediate execution, both statements will return an IQueryable<T>. Until you iterate over your query variable by using a foreach the query variable remains just that.


This article on MSDN should explain things well: Query Execution.


What you are experiencing is called Deferred Query Execution.



In a query that returns a sequence of values, the query variable itself never holds the query results and only stores the query commands. Execution of the query is deferred until the query variable is iterated over in a foreach or For Each loop. This is known as deferred execution.



When you use ToList() what occurs is known as Immediate Query Execution.



In contrast to the deferred execution of queries that produce a sequence of values, queries that return a singleton value are executed immediately. Some examples of singleton queries are Average, Count, First, and Max. These execute immediately because the query must produce a sequence to calculate the singleton result. You can also force immediate execution. This is useful when you want to cache the results of a query. To force immediate execution of a query that does not produce a singleton value, you can call the ToList method, the ToDictionary method, or the ToArray method on a query or query variable.



These are core behaviors of LINQ.





But without ToList() method call at the end of the Where clause, it will return all the Contacts of person.



No, without ToList it will return a query which, when iterated, will yield all of the contacts matching the value you specified to filter on. Calling ToList only materializes that query into the results of that query. Waiting a while and iterating it later, possibly using some other method of iteration such as foreach, will only change the results if the underlying data source (in this case, a database, by the look of thigns) changes its data.


As to your dictionary filter, the same thing applies. Without calling ToList the variable represents a query to get the data when asked, not the results of that query, which is what you would get by calling ToList.


The use of a property versus a field is irrelevant here. Having said that, both queries are using properties, not fields. Even if one did use a field though, it wouldn't change a thing.





But without ToList() method call at the end of the Where clause, it will return all the Contacts of person.



You are wrong.ToList is just forces the iteration and gives you your filtered elements as a List.LINQ uses deferred execution which means until you use foreach loop to iterate over items or use ToList or ToArray methods, it's not executed.So ToList doesn't change your items. Value is also a property (see KeyValuePair<T,K> class), so you are performing a comparison based on property values in both query.There is no difference at all.



Please consider the following statement:


var matches = person.Contacts.Where(c => c.ContactType == searchContact.ContactType).ToList();

This will filter all the records with matching ContactType of searchContact object and returns only the filtered Contacts of person. But without ToList() method call at the end of the Where clause, it will return all the Contacts of person.


Now, consider the following code segment.


Dictionary<int, string> colors = new Dictionary<int, string>(){ {1, "red"}, {2, "blue"}, {3, "green"}, {4, "yellow"}, {5, "red"}, {6, "blue"}, {7, "red"} };
var colorSet = colors.Where(c => c.Value == "red");

This query will filter only the elements with value "red", even without calling ToList() method.


My question is why this two statements (one that compares values and one that compares properties) behave in a different way without ToList() method call? Why this problem does not occur with FirstOrDefault instead of Where clause?


I really appreciate, if anyone can explain the scenario or post some references that I can follow. Thanks!!



You are mistaken. Without calling ToList() or another method to force immediate execution, both statements will return an IQueryable<T>. Until you iterate over your query variable by using a foreach the query variable remains just that.


This article on MSDN should explain things well: Query Execution.


What you are experiencing is called Deferred Query Execution.



In a query that returns a sequence of values, the query variable itself never holds the query results and only stores the query commands. Execution of the query is deferred until the query variable is iterated over in a foreach or For Each loop. This is known as deferred execution.



When you use ToList() what occurs is known as Immediate Query Execution.



In contrast to the deferred execution of queries that produce a sequence of values, queries that return a singleton value are executed immediately. Some examples of singleton queries are Average, Count, First, and Max. These execute immediately because the query must produce a sequence to calculate the singleton result. You can also force immediate execution. This is useful when you want to cache the results of a query. To force immediate execution of a query that does not produce a singleton value, you can call the ToList method, the ToDictionary method, or the ToArray method on a query or query variable.



These are core behaviors of LINQ.




But without ToList() method call at the end of the Where clause, it will return all the Contacts of person.



No, without ToList it will return a query which, when iterated, will yield all of the contacts matching the value you specified to filter on. Calling ToList only materializes that query into the results of that query. Waiting a while and iterating it later, possibly using some other method of iteration such as foreach, will only change the results if the underlying data source (in this case, a database, by the look of thigns) changes its data.


As to your dictionary filter, the same thing applies. Without calling ToList the variable represents a query to get the data when asked, not the results of that query, which is what you would get by calling ToList.


The use of a property versus a field is irrelevant here. Having said that, both queries are using properties, not fields. Even if one did use a field though, it wouldn't change a thing.




But without ToList() method call at the end of the Where clause, it will return all the Contacts of person.



You are wrong.ToList is just forces the iteration and gives you your filtered elements as a List.LINQ uses deferred execution which means until you use foreach loop to iterate over items or use ToList or ToArray methods, it's not executed.So ToList doesn't change your items. Value is also a property (see KeyValuePair<T,K> class), so you are performing a comparison based on property values in both query.There is no difference at all.


0 commentaires:

Enregistrer un commentaire