Debugging C# Code: Techniques and Tools for Professionals

Online Python Trainer for Beginners

Learn Python easily without overwhelming theory. Solve practical tasks with automatic checking, get hints in Russian, and write code directly in your browser — no installation required.

Start Course

Debugging C# Code: From "Why isn't it working?" to "I know where the error is"

\n\n

Every C# developer sooner or later encounters a situation where the code compiles, runs, but does something completely unexpected. Or it crashes with an error that cannot be reproduced in a test environment. In such moments, debugging C# turns from a routine task into a true art.

\n\n

In this article, we will cover techniques and tools that will help you not just find a bug, but do it quickly and efficiently. We won't limit ourselves to the standard F5 — we'll talk about advanced breakpoints, conditional expressions, memory analysis, and even working with dumps in WinDbg. Let's go!

\n\n

Basic but Powerful C# Debugging Techniques

\n\n

Before moving on to exotic tools, let's make sure you're getting the most out of Visual Studio. Many developers only use F9 (set a breakpoint) and F10 (step over), which is a shame.

\n\n

Conditional Breakpoints

\n\n

Imagine: you have a loop with 1000 iterations, and the bug only occurs on the 567th. Set a breakpoint and press F5 567 times? No. Use conditional breakpoints.

\n\n
for (int i = 0; i < 1000; i++)\n{\n    // Some logic\n    ProcessItem(items[i]);\n}
\n\n

Right-click the red breakpoint circle → select "Conditions" → enter i == 567. When the counter reaches the desired value, the debugger will stop automatically. This saves hours of your life.

\n\n

As a condition, you can use not only a comparison but any boolean expression in C#. For example: items[i].IsValid == false && items[i].Id > 100.

\n\n

Breakpoints with Actions (Tracepoints)

\n\n

Sometimes you don't need to stop execution, but simply log something at a specific moment. For this, there are breakpoints with actions. Set a breakpoint, right-click → "Actions" → enter a message like Method called with parameter: {parameter}.

\n\n

This works like Console.WriteLine, but without changing the code. You can output variable values directly to the Output window without interrupting the application.

\n\n

Attach to Process

\n\n

Ever had a bug that only reproduces in production, but not locally? Use Debug → Attach to Process. You can connect to an already running process (e.g., IIS, Windows Service, or a desktop application).

\n\n

Important note: make sure you have PDB files (symbols) for the version of the assembly that is running. Otherwise, instead of variable names, you'll see Variable1 and Variable2.

\n\n

Advanced Techniques: Diagnostics Without Stopping

\n\n

Not all bugs can be caught in the debugger. Sometimes stopping execution changes the program's behavior (e.g., due to timing in multithreaded code). For such cases, there are other C# debugging techniques.

\n\n

Logging with DiagnosticSource and Serilog

\n\n

The built-in System.Diagnostics.Trace is good, but for serious projects, it's better to use structured logging. Serilog is one of the most popular loggers for .NET.

\n\n
using Serilog;\n\nLog.Logger = new LoggerConfiguration()\n    .WriteTo.Console()\n    .WriteTo.File("log.txt", rollingInterval: RollingInterval.Day)\n    .CreateLogger();\n\ntry\n{\n    var result = SomeRiskyOperation();\n    Log.Information("Operation completed successfully. Result: {Result}", result);\n}\ncatch (Exception ex)\n{\n    Log.Error(ex, "Error executing operation");\n}
\n\n

Structured logs allow you to search for errors not by text, but by fields. For example, you can find all logs with OrderId = 12345 from the last hour. This is more powerful than grepping a text file.

\n\n

Profiling and Performance Diagnostics

\n\n

Blogs

Book Recommendations