C#
Completed
-
Section 1: Getting Started
-
Section 2: Core Syntax
-
Section 3: Object-Oriented C#
-
Section 4: Working with Data
-
Section 5: Error Handling
-
Section 6: Delegates and Events
-
Section 7: Async Programming
-
Section 8: More Language Features
-
Section 9: File I/O and Serialization
-
Section 10: Networking in .NET
-
Section 11: The .NET Ecosystem
-
Section 12: Memory and Performance
-
Section 13: Concurrency Beyond Async
-
Section 14: Reflection and Attributes
-
Section 15: Testing and Best Practices
-
Section 16: Design Patterns in C#
-
Section 17: Standard Library Deep Dive
-
Section 18: Data Structures and Algorithms in C#
-
Section 19: GUI and Desktop Development Overview
-
Section 20: Practical Projects
-
Section 21: More Practice Exercises
-
Section 22: More Standard Library and Text Processing
-
Section 23: More Design Patterns
-
Section 24: More Projects
-
Section 25: Interview Practice
-
Section 26: C# Keywords Reference (Modifiers)
-
Section 27: C# Keywords Reference (Statements)
-
Section 28: C# Keywords Reference (Operators)
-
Section 29: BCL: System.Collections.Generic
-
Section 30: BCL: System.Linq
-
Section 31: BCL: System.Threading
-
Section 32: BCL: System.IO
-
Section 33: BCL: System.Text and System.Text.Json
-
Section 34: BCL: System.Net.Http
-
Section 35: C# Language Specification Topics
-
Section 36: More Practice Exercises
-
Section 37: More Async Patterns
-
Section 38: More BCL: System.Reflection and System.Diagnostics
-
Section 39: Nullable Reference Types In Depth
-
Section 40: C# Records and Pattern Matching In Depth
-
Section 41: Dependency Injection Deep Dive
-
Section 42: More Interview and Whiteboard Practice
5: Top-Level Statements
You've probably noticed by now that C# has a habit of wrapping everything in a lot of "ceremony." To write even a single line of logic, you usually need a namespace, a class, and a static Main method. It's structurally sound, but when you're just trying to prototype a quick tool or write a simple script, it feels like a lot of noise.
That's why Top-Level Statements were introduced. They essentially let you tell the compiler: "I know what I'm doing, just assume this whole file is the Main method." It makes your code look much more like Python or JavaScript, which is a breath of fresh air when you're just trying to get something running.
Cutting through the noise with a Quick-Task Logger
Let's build a tiny CLI tool that lets you log a task and timestamps it. In the old days, I'd have to set up a Program class. Now, I can just start typing logic directly into Program.cs. I'm going to start by capturing some user input and printing a formatted string.
Console.WriteLine("What are you working on right now?");
string task = Console.ReadLine();
string timestamp = DateTime.Now.ToString("HH:mm");
Console.WriteLine($"[{timestamp}] Logged: {task}");
That's it. No class, no curly braces, no static void Main(string[] args). The compiler handles all that behind the scenes. I personally love this for "glue code" or small utilities where the overhead of a full class structure just gets in the way of the actual logic.
The "Method Placement" snag
Now, as our tool grows, I want to move the timestamp formatting into its own method to keep the main flow clean. I'll try to define a helper method at the top of the file, because that's where I usually like to put my utilities.
string GetTimestamp()
{
return DateTime.Now.ToString("HH:mm");
}
Console.WriteLine("What are you working on right now?");
string task = Console.ReadLine();
Console.WriteLine($"[{GetTimestamp()}] Logged: {task}");
If you try to run this, the compiler will yell at you. You'll get an error saying that top-level statements must precede any method declarations. I've made this mistake more times than I'd like to admit. In a standard class, you can put methods anywhere. But with top-level statements, the "main" logic has to come first. Anything defined as a method must live at the bottom of the file.
Ordering the logic correctly
To fix this, I just need to shift my helper method to the end. Think of the file as having two zones: the "Execution Zone" at the top and the "Definition Zone" at the bottom.
Console.WriteLine("What are you working on right now?");
string task = Console.ReadLine();
// The execution happens here
Console.WriteLine($"[{GetTimestamp()}] Logged: {task}");
// Now we define our helpers at the bottom
string GetTimestamp()
{
return DateTime.Now.ToString("HH:mm");
}
Now it compiles perfectly. One last thing to keep in mind: you can only have one file with top-level statements in your entire project. If you try to do this in two different files, the compiler won't know which one is the actual entry point of your application, and it'll throw a fit. For everything else in your project, you'll still use the standard class and method structure we've discussed in previous lessons.
📋 Practical Task
Build a Top-Level "Budget Calculator"
Create a new C# console application using top-level statements. Your program should:
- Prompt the user to enter their total monthly budget (as a double).
- Prompt the user to enter a specific expense amount.
- Call a helper method named
CalculateRemainingthat takes the budget and the expense as parameters and returns the remaining balance. - Print the final remaining balance to the console.
Constraint: Ensure your CalculateRemaining method is placed correctly so the code compiles without "top-level statement" ordering errors.
There are no comments for now.