Thursday, December 27, 2007


JustinKohnen: @dcampbell: um... Christmas is over dude ;)

That was posted on Twitter today when I announced that I was working on this very blog entry. Well, I've got news for Mr. Justin "X-mas-Hater" Kohnen. X-mas isn't over until the fat... uhhh... lady sings. (Hmmm... that worked out much better in my head.)

While X-mas day has come and gone, the holiday season continues. I have enough verses left in my song to ensure that our merry-making runs all the way 'til the new year.

"On the eighth day of X-mas my true love (DevExpress) gave to me..."

Bread-and-Butter Refactorings in Query Expressions

Since LINQ is such a big part of what C# 3.0 and Visual Basic 9 are all about, I thought that showing two more examples of refactorings that can be used in query expressions would be useful. The refactorings we'll look at do not target query expressions specifically. Instead, these are pre-existing, bread-and-butter refactorings that have been updated to support query expressions properly.

What's a "bread-and-butter refactoring" you ask? It's one of those refactorings that you can't live without—a part of your everyday arsenal. It's important to know that these crucial refactorings work with the latest and greatest language features.

OK, let's get started!

public static int SumOfEvenSquares(int count)
  return (from number in Enumerable.Range(1, count)
          where (number % 2) == 0
          select number * number).Sum();

There are a number of refactorings that we could apply to the LINQ code above. First, let's use Introduce Local to generate a new local variable assigned to the query expression. This is easy enough to do. Just select the query expression, press the Refactor key (CTRL+` by default), choose Introduce Local, and press ENTER. Below is a screenshot of the preview hint for Introduce Local.

Introduce Local Preview Hint

The More You Know
If you are unfamiliar with Refactor! Pro's preview hints, they are sort of like windows into the future. A preview hint shows what a refactoring will do before you apply it. This feature provides the advantage you need to refactor your code with confidence.

After naming the new local variable, our refactored code looks like so:

public static int SumOfEvenSquares(int count)
  IEnumerable<int> evenSquares = from number in Enumerable.Range(1, count)
                                 where (number % 2) == 0
                                 select number * number;
  return evenSquares.Sum();

View Screencast of Introduce Local in Action!

I would be remiss if I didn't mention that there is another way to use Introduce Local. In addition to pressing the Refactor key, it is also possible to apply the refactoring using cut-and-paste. 99% of the time, when cutting an expression to the clipboard and pasting it within the same method on an empty line above the cut location, the user's intention is to create a local variable assigned to that expression. Refactor! Pro takes advantage of this knowledge to anticipate the user's intent and automatically apply Introduce Local.

View Screencast of Introduce Local Using Cut-And-Paste!

One of the red flags that some have raised against query expressions is their potential to cause code duplication. For example, the expressions in the where and select clauses from the sample code above really should be extracted to new methods. That way, we promote code reuse. If not, we are doomed to write the same tiny, bite-sized expressions over and over. Fortunately, Refactor! Pro's Extract Method refactoring works perfectly on these expressions. With Extract Method, we can easily turn the code above into:

private static IEnumerable<int> GetNaturals(int count)
  return Enumerable.Range(1, count);
private static bool IsEven(int number)
  return (number % 2) == 0;
private static int Square(int number)
  return number * number;
public static int SumOfEvenSquares(int count)
  IEnumerable<int> evenSquares = from number in GetNaturals(count)
                                 where IsEven(number)
                                 select Square(number);
  return evenSquares.Sum();

Believe it or not, using Refactor! Pro, I'm able to produce that code in just 42 keystrokes—including 23 keystrokes for the method names and 12 for navigation and selection. That means that only seven keystrokes are actually needed to apply three Extract Method refactorings!

Curious? View the Screencast of Extract Method in Action!

Finally, I must mention that Extract Method can be used with cut-and-paste just like Introduce Local. That's right, you can cut code to the clipboard and paste it on an empty line outside of a method. Extract Method will take over. Again, Refactor! Pro is working hard to anticipate your intentions.

View the Screencast of Extract Method Using Cut-And-Paste!

And thus ends the eighth verse of my song. Today we've looked at how two bread-and-butter refactorings, Introduce Local and Extract Method, can be used within LINQ expressions. The coolest thing is that all of the screencasts were recorded using Visual Studio 2008. They aren't mock ups of future features. These refactorings work with query expressions this very minute!

My Visual Basic friends might be a little worried because I didn't show these refactorings working in Visual Basic. Well, rest assured, the refactorings work fine. In fact, they work using the same keystrokes!

Now, that's what I call an X-mas present.

posted on Thursday, December 27, 2007 3:38:20 PM (Pacific Standard Time, UTC-08:00)  #    Comments [1]

kick it on