Our last operator is the simplest of all. Really, really simple.
AsEnumerable has a single signature:
public static IEnumerableI can describe its behaviour pretty easily: it returns source.
That's all it does. There's no argument validation, it doesn't create another iterator. It just returns source.
You may well be wondering what the point is... and it's all about changing the compile-time type of the expression. I'm going to take about IQueryable
Now it's not entirely uncommon to want to perform some aspects of the query in the database, and then a bit more manipulation in .NET - particularly if there are aspects you basically can't implement in LINQ to SQL (or whatever provider you're using). For example, you may want to build a particular in-memory representation which isn't really amenable to the provider's model.
In that case, a query can look something like this:
var query = db.Context.Customers
.Where(c => some filter for SQL)
.OrderBy(c => some ordering for SQL)
.Select(c => some projection for SQL)
.AsEnumerable()
.Where(c => some extra LINQ to Objects filtering)
.Select(c => some extra LINQ to Objects projection);
All we're doing is changing the compile-time type of the sequence which is propagating through our query from IQueryable
Sometimes we could do this with a simple cast or variable declaration. However, for one thing that's ugly, whereas the above query is fluent and quite readable, so long as you appreciate the importance of AsEnumerable. The more important point is that it's not always possible, because we may very well be dealing with a sequence of an anonymous type. An extension method lets the compiler use type inference to work out what the T should be for IEnumerable
In short - it's not nearly as useless an operator as it seems at first sight. That doesn't make it any more complicated to test or implement though...
In the spirit of exhaustive testing, I have actually tested:
A normal sequence A null reference A sequence which would throw an exception if you actually tried to use itThe tests just assert that the result is the same reference as we've passed in.
I have one additional test which comes as close as I can to demonstrating the point of AsEnumerable without using Queryable:
[Test]public void AnonymousType()
{
var list = new[] {
new { FirstName = "Jon", Surname = "Skeet" },
new { FirstName = "Holly", Surname = "Skeet" }
}.ToList();
var sequence = list.AsEnumerable();
Assert.IsFalse(sequence.Contains(new { FirstName = "Tom", Surname = "Skeet" }));
}
And finally...
There's not much scope for an interesting implementation here I'm afraid. Here it is, in its totality:
public static IEnumerable{
return source;
}
It feels like a fittingly simple end to the Edulinq implementation.
I think that's all I'm going to actually implement from LINQ to Objects. Unless I've missed something, that covers all the methods of Enumerable from .NET 4.
That's not the end of this series though. I'm going to take a few days to write up some thoughts about design choices, optimizations, other operators which might have been worth including, and a little bit about how IQueryable
Don't forget that the source code is freely available on Google Code. I'll be happy to patch any embarrassing bugs :)


0 comments:
Post a Comment