Linq-i-fying My Existing Projects - Part 1

Published 14 November 07 08:09 AM

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).

image

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.

Comment Notification

If you would like to receive an email when updates are made to this post, please register here

Subscribe to this post's comments using RSS

Comments

# Michael Giagnocavo said on November 14, 2007 1:12 PM:

Defining your own extensions can be useful too. For instance, create something called "IfAny" to encapsulate the common pattern of checking for something and throwing.

# kfarmer@microsoft.com said on November 14, 2007 1:23 PM:

It is also perfectly acceptable not to use query expressions, and instead prefer the dot-syntax.  For example, why do 'from p in Players select p' when just 'players' will do?  Ergo, this may be more readable, since you're doing an identity select:

bool hasUnexpectedPlayers = players.Any(p => !p.GetType().Equals(_expectedPlayerType));

If you were to pass in expected player type as a generic parameter, though:

bool hasUnexpectedPlayers = players.OfType<TExpectedPlayerType>().Any();

Or for that matter, create a new extension:

public static bool IsType(this object obj, Type type)

{

   return obj.GetType().Equals(type);

}

bool hasUnexpectedPlayers = players.Any(p => !p.IsType(_expectedPlayerType));

Leave a Comment

(required) 
(optional)
(required) 

  
Enter Code Here: Required

About hdierking

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.
Page view tracker