C# 3.0 var keyword + Enumerable.AsEnumerable
On my way back from México, I read Pro LINQ: Language Integrated Query in C# 2008. Just like Charles Petzold first introducing WPF through code (and not markup), I like Joseph Rattz’ introduction of LINQ through [extension] methods first instead of the using query expressions. I do think this makes things easier to understand. For me at least. I did not like a big part of the book as it felt more like a reference book. But again, it’s just me.
One thing I disagree with his advice: page 27, he states that one should refrain from using the var keyword just because it’s convenient. I think that:
var integers = new List<int> { 1, 2, 3 };
is clear enough, no need for:
List<int> integers = new List<int> { 1, 2, 3 };
Also, on page 355, he states that strings will get boxed! Although an immutable type behaving like a value type, System.String is not a value type and will thus never be boxed. I guess he meant that the problem with c["Id"] == s["Id"] is that you’re comparing for equality of object reference you’re not comparing the content of the String instances.
Now, one thing I tend to forget when talking to developers is that some are still trying to grasp the idea of generics. And that’s exactly what I thought about when seeing Enumerable.AsEnumerable:
public static IEnumerable<TSource> AsEnumerable<TSource>(this IEnumerable<TSource> source) {
return source;
}
Why would anyone need to use what looks to be such a useless code method? Look at this query expression:
var query = from dr in orderDataTable.AsEnumerable()
select dr.Field<int>("OrderID");
If I’d like to cast OrderTable to a generic version of IEnumerable<T>, what value of T should I pick? In this example, the answer might be easy as DataTableExtensions.AsEnumerable(this DataTable source) returns an EnumerableRowCollection<DataRow> instance: we can cast to IEnumerator<DataRow>.
Both would work:
var query = from dr in (IEnumerable<DataRow>) orderDataTable
select dr.Field<int>("OrderID");
and
var query = from dr in orderDataTable as IEnumerable<DataRow>
select dr.Field<int>("OrderID");
But as soon as you have anonymous types involved, doing something like this is impossible: you don’t know the compiler generated name of those types! What would you use as the generic IEnumerable type parameter (you know, the T in IEnumerable<T>)?
The purpose of what looks like the simplistic Enumerable.AsEnumerable() method is hidden in its signature: the compiler will get you the right T to use in IEnumerable<T>, no need to know what it is.
OK. I’m no LINQ expert but by writing this, I’m clarifying my thoughts. I hope this helps.
Bonne nuit les petits.
Comments
- Anonymous
January 10, 2008
Actually, this is arguably more of a side-effect. AsEnumerable is mostly useful for when you want to drop out of using extensions for one type (for example, IQueryable<T> or the DataSetExtensions) and instead start using the IEnumerable extensions. You'll note there's also an AsQueryable method which has similar purpose.