Wednesday, June 23, 2010

Let in LINQ to Objects

when i was working with the linq i found something useful called the let keyword basically useful when we work with collection of inherited type

To take a simple example, suppose we have int[] values. We could write the following query to double all the values

var query = from i in values
select 2 * i;

With the let keyword, this could be rewritten as

var query = from i in values
let doublei = 2 * i
select doublei;

I'll give a slightly more interesting example in a moment, but this simple example lets us easily look at what actually gets generated. After firing up Reflector, it seems that the compiler treats the code above as though we'd typed

var query = from temp in
(
from i in values
select new { i, doublei = 2 * i }
)
select temp.doublei;

So each time you add a let statement into your query, the compiler creates a new subquery that returns an anonymous type composed of the original value plus the new value specified by the let.

For a more interesting example of this, suppose we have IEnumerable fileSystemInfos, and that we want to pick out the files (i.e. ignore directories) where the size is under 1000 Bytes. We could use the following query

var query = from fileSystemInfo in fileSystemInfos
where fileSystemInfo is FileInfo && ((FileInfo)fileSystemInfo).Length < 1000
select (FileInfo) fileSystemInfo;

This code requires the cast to FileInfo in order to access the Length property, and again to ensure that we return the correct type in the query. Using let, we can perform the cast in a single place

var query = from fileSystemInfo in fileSystemInfos
where fileSystemInfo is FileInfo
let fileInfo = (FileInfo)fileSystemInfo
where fileInfo.Length < 1000
select fileInfo;

I think that this version is probably more readable, and if we had more constraints in the where clause that needed the FileInfo rather than FileSystemInfo then the let version would show a bigger difference. Again, the compiler seems to treat the above query as though it was written as


var query = from temp in
(
from fileSystemInfo in fileSystemInfos
where fileSystemInfo is FileInfo
select new { fileSystemInfo, fileInfo = (FileInfo)fileSystemInfo }
)
where temp.fileInfo.Length < 1000
select temp.fileInfo;


Having used LINQ to Objects a reasonable amount, I found it interesting to come across a new keyword and was curious to find out how it works - hopefully this post gives an explanation!

0 comments:

Post a Comment