Linq Cautions

Linq is a great addition to .NET, and I found that it has worked well in many situations, although I'm just starting to learn how to use Linq.

However, in the reading that I was doing about Linq, I found that there are some subtle things that a developer should keep an eye on that can lead to trouble.

I included one specific caveat that I discovered was the result of delayed execution.

So, I wonder what other caveats exist for Linq that developers familiar with Linq should be aware of.

+6
linq
source share
3 answers

Creating a query in a foreach loop

IEnumerable<char> query = "Not what you might expect"; foreach(char vowel in "aeiou") { query = query.Where(c => c != vowel); } 

The above code only removes โ€œuโ€ from the string due to delayed execution.

To remove all vowels, you need to do the following:

 IEnumerable<char> query = "Not what you might expect"; foreach(char vowel in "aeiou") { char temp = vowel; query = query.Where(c => c != temp); } 
+5
source share

I think LINQ is pretty solid, and there aren't many big reservations. Almost every โ€œproblemโ€ I have encountered is the result of deferred execution, and this is not a problem, but rather a different mindset.

The biggest problem I encountered - LINQ is the game changer (or at least the rule bend) when it comes to profiling for performance. Delayed execution can make it difficult to temporarily profile an application, and it can also unexpectedly change performance parameters at runtime. Some LINQ operations seem almost magical how fast they are, while others take a lot longer than I expected - but this is not always obvious from the results of the code or profiler.

Moreover, as a rule, delayed execution more than compensates for cases when it slows down manual procedures. I prefer simpler, cleaner code to the code that it replaced.

In addition, I found that the more I use LINQ for objects, the more I have to rethink my design and rework my collections as a whole.

For example, I never realized how often I showed IList instead of IEnumerable when it was not absolutely necessary, until I started using linq for objects often. Now I fully understand why MS design guidelines warn about using IList too often (for example, not returning IList only for the Count property, etc.). When I would have methods that accept IList, passing the IEnumerable results from the linq request requires .ToList () or a redesign of the method API.

But this is almost always worth rethinking - I found many places where passing an enumerable and using LINQ led to a huge perf. arrived. Delayed execution is great if you think about it and make full use of it. For example, using .Take () to limit the collection to the first 2 elements, if all that was needed was a little more complicated than pre-linq and dramatically accelerated some of my more annoying loops.

+3
source share
Good question. As Reed points out, they all mostly stem from deferred execution (but unlike him, I consider this a drawback). Just thinking why deferred executions are not performed by remembering the state). Here are a few examples - all these are more or less variants of the problem of delayed execution.

1) I'm too lazy to do something on time

Linq is available on demand only.

The common mistake is newbies (I included in the past) make does not know about deferred execution. For example, something like

  var p = listOfAMillionComplexItems.OrderBy(x => x.ComplexProperty); 

works in an instant, but the actual sorting does not end until you list the list, in other words, the execution will not be completed until you need the result of the execution. To execute it, you need something like:

 foreach(var item in p)... //or p.Count(); //or p.ToList(); //etc 

See them as SQL queries. if you have

 var query = from i in otherValues where i > 5 select i; 

consider it akin to writing

 string query = "SELECT i FROM otherValues WHERE i > 5"; 

Does the last call to db? Not. You should

 Execute(query); 

This is the same with Linq.

2) I live in the present

Be careful when changing variables inside Linq expressions later.

To be safe, first create backup variables, and then use a backup in the query if the variable may change later before the query actually executes.

From here:

 decimal minimumBalance = 500; var customersOver500 = from c in customers where c.Balance > minimumBalance select c; minimumBalance = 200; var customersOver200 = from c in customers where c.Balance > minimumBalance select c; int count1 = customersOver500.Count(); int count2 = customersOver200.Count(); 

Suppose we have four clients with the following balances: 100, 300, 400 and 600. What will count1 and count2 be? They will be equal to 3. "customerOver500" refers to the variable "minimumBalance", but the value is not obtained until the query results are repeated (through the for / each loop, ToList () or even "Count (), as shown above) At the time when the value is used to process the request, the value for minimumBalance has already changed to 200, so both LINQ queries give the same results (clients with a balance of more than 200).

3) My memory is too weak to remember the values โ€‹โ€‹of the past

Same as above, context is slightly different.

or is it from the same site:

Consider this simple example method using LINQ-to-SQL to get a list of clients:

 public IEnumerable<Customer> GetCustomers() { using(var context = new DBContext()) { return from c in context.Customers where c.Balance > 2000 select c; } } 

It seems pretty harmless - until you get an "ObjectDisposedException" when trying and listing the collection. What for? Because LINQ does not actually execute the query until you try and list the results. The DBContext class (which provides the Customers collection) is deleted when this call completes. After you try and list through the collection, it refers to the DBContext.Customers class and you get an exception.

4) Don't try to catch me, I can still slip away

Try-catch is meaningless for statement if it is not reasonable to use it.

Instead, it will work better with exception handling.

 try { wallet = bank.Select(c => Convert.ToInt32("")); } catch (Exception ex) { MessageBox.Show("Cannot convert bad int"); return; } foreach(int i in wallet) //kaboom! 

We also do not receive the correct error message, and the function does not close return .

5) I am not only unloving, but also not involved in mistakes

Linq is executed every time you list them. Therefore, do not reuse Linq enumerations.

Suppose you have an IQueryable or IEnumerable expression returned from a Linq expression. Now enumerating the collection will execute the statement, but only once? No, every time you do it. It has bitten me in the past. If you have:

 var p = listOfAMillionComplexItems.OrderBy(x => x.ComplexProperty); MessageBox.Show(p.Count().ToString()); //long process. MessageBox.Show(p.Count().ToString()); //long process still. 

So do it better

 int i = p.Count(); //store in a variable to access count //or better var list = p.ToList(); //and start using list 

6) If you do not know how to use me, I can cause side effects!

The same as above just shows how reusing Linq enumerations can lead to unwanted behavior.

Make sure you are not performing side effects (since re-enumeration in Linq is much more common). To give a wild example,

 p = bag.Select((t, i) => {if(i == 1) MessageBox.Show("Started off"); return t;}); 

If you list twice, you know that an unwanted thing may happen.

7) Be careful with the order I am doing when chaining

Not only for variables, even chained Linq functions can execute in a different order from what you usually expect (although the behavior is correct). Do not think about the need (step by step), think about how Linq can fulfill it.

For example,

 var d = Enumerable.Range(1, 100); var f = d.Select(t => new Person()); f = f.Concat(f); f.Distinct().Count() ?? 

What will be the number of individuals in f ? I think 100, no, but it's 200. The problem is that when the actual execution of the concatenation logic is executed, f is still d.Select(t => new Person() not executed . Thus, this effectively gives in

 f = d.Select(t => new Person()).Concat(d.Select(t => new Person())); 

which then has 200 different members. Here is a link to the actual problem

8) Hey, we are actually smarter than you think.

Not a reservation in itself, but there are many cases where Linq can surpass your real style program. Therefore, before optimization, give a second thought and even a guideline.

The reason that delayed execution is mostly done on demand makes Linq much more efficient than it seems. The iterator block "gives" one element at a time as required, providing the ability to stop execution when it is no longer needed. Here is a very good question that describes this in detail: Does the order of LINQ extension methods not affect performance?

9) I did not want a number crunch

Overuse of Linq can make code inefficient as well as less readable.

Linq is not the right tool for number crunching algorithms, especially for large datasets whose complexity can scale exponentially. Sometimes only two cycles would be better. The same can be applied to raw SQL compared to LINQ to SQL.

10) Hire me for the right job

Asking Linq to keep in mind your regular business is a poor choice of software that runs counter to readability.

Some for example:

 medicines.Any(p => { Console.WriteLine(p); return false; }); 

to intercept on an enumerable.

or

 medicines = medicines.Select(p => { p.Id = 3; return p; }); 

Just bad tools.

11) Debugging and profiling can be a nightmare

It's hard to keep track of what's happening under the hood, the Linq expression from VS

Not that it was completely impossible, but its task bit debugged the linq query as efficiently as non-linq code from VS itself. Profiling also gets a little more complicated due to the nature of deferred execution. But this should not stop anyone from doing the trivial one or two liners!


A bunch of reservations related to deferred execution more or less! This question is here . Some related readings on SO:

Examples when not to use LINQ

Pros and cons of LINQ (language integral query)

What is the biggest mistake people make when using LINQ?

disadvantages of linq

+1
source share

All Articles