LINQ queries return queries not data
The title of this article is a pretty obvious statement, but it’s actually pretty easy to forget and it can lead to some painful bugs. Here’s a code snippet whose output may seem surprising:
Module Module1
Sub Main()
Dim query =
From name In {"one", "two", "three"}
Select New User(name)
Dim x = query.First
Dim y = query.First
Console.WriteLine(x Is y)
Console.ReadKey()
End Sub
End Module
Public Class User
Public Sub New(ByVal username As String)
Console.WriteLine("Creating user: " & username)
End Sub
End ClassAt first glance it looks like x and y are the same object, but since query is just a query, not an actual collection, the result will be fetched independently each time you call First. When the code is run, the console output looks like this:
Creating user: one Creating user: one False
This shows that the constructor was called twice for the same string, which explains why x and y are actually different objects. In a case like this it is better to put ToList at the end of the query:
Dim users = (From name In {"one", "two", "three"} Select New User(name)).ToList()
Bugs like this can be particularly problematic when you pass around an object of type IEnumerable and the programmer assumes that they are dealing with a collection, when they are really dealing with a query. So… watch out!