Debugging and Diagnostics
Level: Intermediate
- Breakpoint types and conditions
- Watch windows and variable inspection
- Exception handling and debugging
- Debug console and immediate window
- Performance profiling
- Diagnostic tools
Breakpoint Types
Simple Breakpoint
Click left margin → F9 to toggle:
public class StudentService
{
public Student GetStudent(int id)
{
// Breakpoint here - execution stops
var student = _repository.GetStudent(id);
return student;
}
}
Red dot = breakpoint active.
Conditional Breakpoint
Right-click breakpoint → Filter...:
Filter: id == 101
Hit Count: 1
Stop only when condition true.
Tracepoint
Right-click breakpoint → Actions... → "Print a message":
Breakpoint message: Student retrieved: {student.Name}
Logs to output without stopping.
Watch Window
Debug → Windows → Watch:
var student = new Student
{
RollNumber = "SMS-2024-001",
Name = "Ravi Kumar",
ClassName = "10-A",
Status = "Active"
};
// In Watch window, add:
// student.RollNumber
// student.ClassName
// student.Status == "Active" ? "OK" : "INACTIVE"
Watch expressions evaluate during execution.
Locals Window
Debug → Windows → Locals — auto-shows all local variables:
public void ProcessFeePayment(int studentId, decimal amount)
{
// Locals shows:
// studentId = 101
// amount = 5000
var payment = new FeePayment { Amount = amount };
// After this line, Locals shows:
// payment = { Amount: 5000, PaidOn: null }
}
Updates automatically at each step.
Immediate Window
Debug → Windows → Immediate (execute code during debug):
// While paused, type in Immediate window:
? student.Name
// Output: "Ravi Kumar"
? student.Status == "Active"
// Output: true
student.ClassName = "10-B"
// Modify variable during debug
Execute statements without stopping execution.
Exception Handling Debugging
Break on exceptions:
Debug → Windows → Exception Settings:
☑ Common Language Runtime Exceptions
☑ Advanced debugging features
Stop when exception thrown:
public Student GetStudent(int id)
{
try
{
if (id <= 0)
throw new ArgumentException("Invalid student ID");
return _repository.GetStudent(id);
}
catch (Exception ex)
{
// Debug breaks here on exception
// Inspect ex.Message, ex.StackTrace
throw;
}
}
Call Stack Window
Debug → Windows → Call Stack — shows execution path:
> GetStudent(int id) - StudentService.cs:25
> GetStudentList() - StudentController.cs:12
> Main(string[] args) - Program.cs:5
Click frame to jump to that code location.
Threads Window
Debug → Windows → Threads — monitor parallel execution:
For SMS background processing:
// Thread 1: Main UI thread processing student list
// Thread 2: Background thread calculating fees
// Thread 3: Async email notifications
// Threads window shows all active threads
// Set which thread to debug
Performance Profiler
Debug → Performance Profiler:
- Select "CPU Usage"
- Start recording
- Navigate through SMS (student list, create exam, etc)
- Stop recording
- Analyze hot spots:
StudentService.GetStudents() - 45% CPU
ExamService.CalculateResults() - 30% CPU
FeeCalculation() - 15% CPU
Identify bottlenecks.
Memory Diagnostic Tools
Debug → Performance Profiler → Memory Usage:
- Snapshot heap
- Perform actions (add 1000 students, download reports)
- Snapshot again
- Compare:
Before: 50 MB
After: 250 MB
Growth: 200 MB (mostly Student objects)
Find memory leaks.
SMS Debugging Scenario
Debug student fee calculation:
public decimal CalculateTotalFees(int studentId)
{
var student = _studentService.GetStudent(studentId); // Breakpoint 1
var classRate = GetClassFeeRate(student.ClassName); // Breakpoint 2
var discount = GetDiscount(student.Status); // Breakpoint 3
decimal totalFees = 0;
if (student.Status == "Active")
{
totalFees = classRate - discount; // Breakpoint 4 - watch (totalFees)
}
return totalFees; // Expected: 50000
}
Step through, inspect variables at each stage.
Debug Output Window
Debug → Windows → Output:
Logs from Debug.WriteLine():
public void CreateStudent(Student student)
{
Debug.WriteLine($"Creating student: {student.Name}");
Debug.WriteLine($"Class: {student.ClassName}");
_repository.Add(student);
Debug.WriteLine($"Student {student.Id} created successfully");
}
// Output window shows:
// Creating student: Priya Sharma
// Class: 10-B
// Student 102 created successfully
Key Shortcuts
| Shortcut | Action |
|---|---|
F5 | Start debugging |
F9 | Toggle breakpoint |
F10 | Step over |
F11 | Step into |
Shift + F11 | Step out |
Ctrl + Alt + W | Open Watch window |
Ctrl + Alt + L | Open Locals window |
Ctrl + Alt + I | Open Immediate window |
Ctrl + Alt + C | Open Call Stack |
Key Takeaways
- Breakpoints = pause execution to inspect state
- Watch window = monitor variables over time
- Exceptions = catch and understand errors
- Call stack = understand execution flow
- Performance profiler = find bottlenecks
- Memory diagnostics = find leaks
Use tracepoints instead of Console.WriteLine() — no code changes, automatic logging during debug.
- Not clearing breakpoints — Old breakpoints remain, slow debugging
- Watching too many variables — Performance impact
- Forgetting to stop debugging — Resource leak
- Not checking Exception Settings — Miss important exceptions
Use ChatGPT, Claude, or Copilot to go deeper on Visual Studio Debugging. Try these prompts:
"How do I set a conditional breakpoint?""What's the difference between Step Over and Step Into?""How do I find memory leaks?""Quiz me on debugging"
💡 Tip: After reading this article, paste your own code into AI and ask "What could go wrong here and why?" — fastest way to find edge cases and deepen understanding.