A LINQ Tutorial
As part of my on-going exploration of technologies related to programming Silverlight and Windows Phone, I’ve been exploring LINQ in some detail.
Today, I’d like to take a look at how LINQ queries are executed; specifically focusing on the delay in execution that makes LINQ so performant.
[Double click on image for full size]
To begin, divide your main page vertically into two equal columns, and add a ListBox to each column, as shown in the following Xaml,
<Grid x:Name="ContentPanel" Grid.Row="1" Margin="12,0,12,0"> <Grid.ColumnDefinitions> <ColumnDefinition Width="1*" /> <ColumnDefinition Width="1*" /> </Grid.ColumnDefinitions> <ListBox Name="DeferredLB" Grid.Column="0" Margin="10" HorizontalAlignment="Stretch" VerticalAlignment="Stretch" /> <ListBox Name="NotDeferredLB" Grid.Column="1" Margin="10" HorizontalAlignment="Stretch" VerticalAlignment="Stretch" /> </Grid>
To demonstrate that LINQ uses deferred execution, we’ll set up a query that relies on a method call. Inside the method call, we can add to the ListBox so that we can see which method is running at any given moment.
public MainPage( ) { InitializeComponent( ); int[] primes = { 1, 2, 3, 5, 7, 11, 13, 17, 19 }; var query = from prime in primes select Doubler( prime, DeferredLB ); foreach ( var n in query ) DeferredLB.Items.Add( n ); } private static int Doubler( int n, ListBox lb ) { lb.Items.Add( "Doubling " + n ); n *= 2; return n; }
When you run this application, you see that control bounces back and forth from the query in Main to the Doubler method as each item is yielded in the enumerator that is implicitly called by the foreach loop. The query is not executed until needed and if you were to cut off the query half way through then the remaining values would never load into memory.
To nail this down, let’s force the query to be executed all at once. To do this, all we do is to convert the query to a list. This forces the query to execute in full (to populate the list) and then we can iterate through that list all in one go. We’ll populate the right hand list box with the results of that approach:
public MainPage( ) { InitializeComponent( ); int[] primes = { 1, 2, 3, 5, 7, 11, 13, 17, 19 }; var query = from prime in primes select Doubler( prime, DeferredLB ); foreach ( var n in query ) DeferredLB.Items.Add( n ); query = from prime in primes select Doubler( prime, NotDeferredLB ); foreach ( var n in query.ToList( ) ) NotDeferredLB.Items.Add( n ); }
The result is shown in the image at the top of this posting.
Note that we use an array and the compiler optimizes enumeration of arrays, but that does not affect the point made in this discussion.
you are in point of fact a just right webmaster. The site loading pace is incredible. It seems that you are doing any unique trick. In addition, The contents are masterpiece. you have performed a fantastic job on this matter!
Nice article with very simple approcah to make understand the tricky concept!!!!
Thank you very much about your instruction when I have come to your web
Usually not a good idea to do this for the following reason: if you have some complex creation of a list, and you do it in a deferred manner (i.e. you are using operators like Union and Where), the creation of that list will happen on the UI thread.
It’s better to just do all work on a background thread, and call “ToList” to ensure the list is actually created on that background thread, before returning that list to the UI.