Wednesday, June 12, 2013

How to write a loop, or lambda expression, in the immediate window

First, you can't write lambda expressions in the immediate window. There are some very good, boring reasons why this is the case. Jared Par explains here...

However, what you really wanted to do is write a loop inside the immediate window because there is some particular debugging goal that you are trying to achieve. This post is about how you can do that.

For example, let's say we have an array of a large number of elements, 1000 or so should do. Let's also say that there is one piece of data in that array that is relevant. We wish to inspect each element individually and test the validity of each item. The following code snipped creates this situation.

static void Main(string[] args)
{ 
  List<int> ints = new List<int>();
  for (int i = 0; i < 1000; i++)
  {
    ints.Add(i);
  }
 
 
  Random random = new Random();
  ints[random.Next(1000)] = -12;
  Console.ReadLine();
}

In this artificial case we're looking for the index of the element in the array that is equal to -12.

The immediate window forces us to do this one item in the array at a time. Potentially taking 1000 user-interactive steps.

Since that method sucks, here's an alternative:
  1. Run the program in the debugger and set a breakpoint on the ReadLine() statement.
  2. Open up the nuget package manager console.
  3. Write some clever powershell that does the evaluation and looping for us.
The clever bit of powershell code that is necessary starts with something like this:

$dte.Debugger.GetExpression("expression", 1, $true)

$dte is the variable that contains the Visual Studio automation model.
Documentation about $dte is here.

In our case, the completed powershell expression looks like this:

for($i = 0; $i -lt 1000; $i++) { $a = $dte.Debugger.GetExpression("ints[$i]"); if ($a.Value -ne $i) { Write-Host $a.Value $i } }

Or, broken into multiple, more readable lines:

for($i = 0; $i -lt 1000; $i++) {
  $a = $dte.Debugger.GetExpression("ints[$i]");
  if ($a.Value -ne $i) {
    Write-Host $a.Value $i
  }
}

This rather neatly writes out the index we're looking for and the value found there. 



















The anomalous value (-12) wound up in the 604th element of the array. Groovy.

Most programmers aren't going to do this. It requires good knowledge of powershell, some knowledge of the Visual Studio automation model, and an interesting and difficult debugging problem before it is useful.

But it is fun.

7 comments:

  1. Thank you! This is great! Love your writing style, too. :)

    ReplyDelete
  2. Just FYI: Quick Basic 4.5 in 1988 allowed a for loop in the immediate window.

    ReplyDelete
  3. Still useful in 2014-08! Thank you, sir!

    ReplyDelete
  4. Just wanted to pass on my thanks, as well. This came in very handy.

    ReplyDelete
  5. Helped me a lot at work, thanks !

    ReplyDelete
  6. w00t - this is very helpful, thank you!

    ReplyDelete