Common Linq / Standard Query Operator Errors / Wrong Steps?

For programmers who do not come from the functional background of programming, are there any errors that should be avoided?

+3
c # linq
source share
4 answers

The biggest mistake people tend to make is a misunderstanding of the rules of laziness and evaluation for the LINQ query:

Requests are lazy: they are not executed until you go through them:

// This does nothing! No query executed! var matches = results.Where(i => i.Foo == 42); // Iterating them will actually do the query. foreach (var match in matches) { ... } 

In addition, the results are not cached. They are computed every time you iterate over them:

 var matches = results.Where(i => i.ExpensiveOperation() == true); // This will perform ExpensiveOperation on each element. foreach (var match in matches) { ... } // This will perform ExpensiveOperation on each element again! foreach (var match in matches) { ... } 

Bottom line: Know when your requests are being executed.

+11
source share

For programmers who do not come from the functional background of programming, are there any errors that should be avoided?

Good question. As Judah points out, the biggest thing is that the query expression builds the query; it does not execute the query that it creates.

The immediate consequence of this fact is that you execute the same query twice to return different results.

The immediate consequence of this fact is that the query is executed for the second time, not reusing the results of the previous execution, as new results may differ.

Another important fact is that queries are best to ask questions, rather than change state. Try to avoid any queries that directly or indirectly force something to change its meaning. For example, many people try to do something like:

 int number; from s in strings let b = Int32.TryParse(s, out number) blah blah blah 

It just asks for a world of pain, because TryParse mutates the value of a variable that is outside the query.

In this particular case, you better do

 int? MyParse(string s) { int result; return Int32.TryParse(s, out result) ? (int?)result : (int?)null; } ... from s in strings let number = MyParse(s) where number != null blah blah blah... 
+4
source share

IMO, when you come across LINQ, you should know these topics (they are big sources of errors):

Delayed execution (in SO format)

Closing (on SO - 1)

Closing (on SO-2)

Closing (Eric Lippert Blog)

+3
source share

Understanding the semantics of closures .

Although this is not a problem limited to LINQ queries only, private variables are more likely to occur in LINQ because it is one of the most common places where lambda expressions are used.

While closures are very useful, they can also be misleading and lead to incorrectly incorrect code. The fact that closures are "live" (which means that changes to variables outside the captured expression are visible to the expression) is also unexpected for some developers.

Here's an example of where closures create problems for LINQ queries. Here, the use of closures and deferred execution are combined to produce incorrect results:

 // set the customer ID and define the first query int customerID = 12345; var productsForFirstCustomer = from o in Orders where o.CustomerID = customerID select o.ProductID; // change customer ID and compose another query... customerID = 56789; // change the customer ID... var productsForSecondCustomer = from o in Orders where o.CustomerID = customerID select o.ProductID; if( productsForFirstCustomer.Any( productsForSecondCustomer ) ) { // ... this code will always execute due to the error above ... } 

This query will always enter the body of the if() { } operator, because by changing the value of customerID , it affects the execution of both queries - they actually use the same identifier, since the customerID variable is fixed in both LINQ statements.

+3
source share

All Articles