Introduction
I received a WPF project I never touched before, and my first instinct after looking around is to run the application and see what it actually does. After that, the next logical step for me is to put a bunch of breakpoints to make sure I covered most scenarios.
For that, I use a Visual Studio plugin called Breakpoint Generator. But there were three issues in this case with that plugin:
- The plugin will only place breakpoints to
public
methods. - When presented with a lot of classes and methods, the plugin starts misbehaving, showing a class as having breakpoints when it didn’t.
- After a certain number of breakpoints, Visual Studio starts slowing down, and it gets more and more difficult to add new breakpoints.
An idea came to mind then which required me to do a backup of the solution just in case. So I came up with a small little LINQPad script (you guys remember our last post on LINQPad, right? :D ) that goes like this:
var dir = new DirectoryInfo(@"F:\Tryouts");
foreach (var file in dir.EnumerateFiles("*.cs", SearchOption.AllDirectories).Where
(a => !a.Name.Contains(".g.cs") && !a.Name.Contains(".g.i.cs") && !a.Name.Contains(".Designer.cs")))
{
var lines = File.ReadAllLines(file.FullName);
for (int i = 0; i < lines.Length; i++)
{
if (Regex.IsMatch(lines[i], "^.*{$") && Regex.IsMatch(lines[i - 1],
@"\(.*\)") && !Regex.IsMatch(lines[i - 1], "switch"))
{
lines[i] = lines[i].Replace("{", "{\n /* ToRemove:GeneratedBreakPoint */
if (System.Diagnostics.Debugger.IsAttached) {System.Diagnostics.Debugger.Break(); }");
}
}
File.WriteAllLines(file.FullName, lines);
}
So let’s analyze this first:
- On line 1 – we define the directory where the project is
- On line 2 – we enumerate through each C# file but we discard the display and generated files since playing with those (to which we normally don’t even have access to from inside Visual Studio).
- On line 4 – we read all of the lines inside the file into a variable called
lines
- On line 6 – we are going to use a
for
loop to iterate through the lines. The reason for reading the lines in a variable and looping over them like this is because we have a condition dependant on the previous line, and this way, we can access it without the restrictions of a foreach
enumerator. - On line 8 – we check if the like contains an open curly brace and that the line above it also contains parenthesis but not a
switch
statement. If we were to add this to the code without the conditions, we would be adding breaks to classes instead of methods and to switches which will break the code. - If the condition on line 8 is
true
, then we append a string
that contains a comment (this is for clean-up if I don’t delete them manually); an if
command that checks if the debugger is attached (in case one slip) and if we have the debugger attach then we put a break. - On line 15 – we just write to the same file the contents we modified.
Because we are modifying the files, I made a back-up of the project. Also, LINQPad helped out a lot in prototyping this. I know it’s not the most pretty code, but it does the job.
The benefits that came out from this are:
- I got breakpoints in all the methods,
public
and private
, all the loops and conditions - It’s highly customizable since I can write any logic for this
- Low memory footprint on Visual Studio since it don’t have to keep the breakpoints loaded
- I can switch the breakpoints for tracers or loggers
This way, I can go through the code, removing them one by one as I encounter them (“Edit and Continue” helps a lot here) and I know if I didn’t cover a specific functionality in my inspection. I know this might sound tedious but as long as it helps, I say go for it, better to do it like this than to break something down the line.
The main idea behind this is finding a solution that goes outside the IDE to solve a particular issue, in this case learning the application.
Side Story: At one point, we had a few massive projects with several solutions in them in a mix of C# and C++, in such cases, it was easier to spin off a script like this to look for some text (and also make it run on multiple threads) than opening it up in Visual Studio.
I hope you enjoyed this little adventure.
Thank you for reading!
CodeProject