Linq-i-fying My Existing Projects - Part 1
To be honest, I don't know how many parts there will end up being - since the longer I'm away from day to day developing, the fewer projects I have to go back through. However, I can think of a few more off the top of my head - so I still think that "Part n" is a fair statement.
Anyway, for a sample golfing application, I have the following hierarchy (fragment).
Now, ignoring for the moment the fact that I didn't make Round a generic and thereby avoid the need for it, the following method in Round validates that either Players or Teams can play a round of golf, but not a mixture of both (e.g. - a single player cannot go up against a team).
private void ValidatePlayerTypeConsistency(Player[] players) {
foreach (Player player in players) {
if (!player.GetType().Equals(_expectedPlayerType))
throw new ArgumentException("Player was not of the expected type ('" +
_expectedPlayerType.FullName + "')");
}
}
Using a C# 3.0 Linq query, the imperative structure of the foreach loop can now be replaced with a more declarative one as follows.
private void ValidatePlayerTypeConsistency(Player[] players) {
bool hasUnexpectedPlayers = (from p in players select p)
.Any(p => !p.GetType().Equals(_expectedPlayerType));
if(hasUnexpectedPlayers)
throw new ArgumentException("Player was not of the expected type ('" +
_expectedPlayerType.FullName + "')");
}
A couple of quick things to notice here:
- In the Linq query, the C# 3.0 language extensions do not cover the entire breadth of Linq functionality (e.g. - the "Any" quantifier). When you run into cases like this, remember that it is perfectly acceptable to mix the language extensions syntax with the standard extension method/lambda syntax. You can do this by simply enclosing the language extensions syntax block in parentheses and then calling additional methods on the result.
- My Linq query syntax didn't really reduce my total line count and the declarative syntax is arguably harder to read. To this, I can only say a) this is a really simple example and b) like anonymous delegates and generics, you get used to it. That said, this example should illustrate that you should take a pragmatic approach to incorporating new features like Linq into your applications.
A final note here - I am ONLY able to do this type of code replacement because I have a great set of unit tests backing me up. In fact, when I first tried out the Linq approach, my test failed. DO NOT make changes like this to working applications without having good tests to back you up.
Hopefully, I'll bring you some more complex examples soon.
I am currently the Editor-in-Chief for MSDN Magazine. I joined Microsoft in 2006 as a product planner with the certification team at Microsoft Learning. Prior to that, I spent my career as a developer and later as an architect. My main technology passions include pretty much anything on language theory, agile development, and service-oriented architecture.