Monday 16 November 2009

SelectMany; combining IDisposable and LINQ

Something that often trips me up in LINQ is that you frequently have to break out of the query syntax simply to add a few “using” blocks. It is important to keep the “using” to ensure that resources are released ASAP, but the regular LINQ query syntax doesn’t let you do this. For example (and I realise there are better ways of doing this – it is for illustration only):

image

Trying to write this (or something like this) in LINQ query syntax (or fluent syntax) just gets ugly.

If only there were a way to convince it to run the “Dispose()” for us as part of the query! A “let” looks promising, but this won’t do anything special in the error case. But there is a pattern (other than just “using”) that lets us conveniently run code at the end of something… “foreach”. And both query-syntax and fluent-syntax already play nicely with extra “foreach” blocks – it falls (loosely) into “SelectMany”.

Thoughts; we could write an extension method that turns “IDisposable” into “IEnumerable”:

image

image

This is a step in the right direction – but those hanging “Using” blocks bother me - and the disposable object isn't quite inside the iterator - there are probably some corner-cases that would lead to items not getting disposed. But LINQ syntax is purely a query comprehension syntax; we aren’t limited to the current conventions – we can write an alternative version of “SelectMany”:

image

(hey, I never said SelectMany was pretty!)

This allows a much more interesting use:

image

This now does everything we want, without any ugly – our disposable items get disposed, and we can write complex chained queries.

I still haven’t decided whether this is too “out there” – i.e. whether it adds more benefit than it does confusion. All thoughts appreciated!