Your First C# Program
Every C# journey starts with a small program that compiles, runs, and prints output.
Introduction
Every C# journey starts with a small program that compiles, runs, and prints output. Understanding entry points, namespaces, and the difference between top-level statements and classic Main methods is essential for reading enterprise codebases.
In .NET 6+, console templates use top-level statements by default — a single file runs without explicit class boilerplate. Larger applications still use classes, dependency injection, and multiple projects. This lesson shows both styles so you are not confused when opening a bank's payment service repository.
You will compile with dotnet build, run with dotnet run, pass command-line arguments, and interpret exit codes — the same flow used in automated tests and Docker HEALTHCHECK scripts.
The story
A payroll company ships a nightly console tool that HR teams run from the command line: PayrollExport.exe March2026. If the employee forgets the month argument, the program must exit with a clear error message and a non-zero code so automated schedulers know the job failed.
Understanding entry points, namespaces, and exit codes is how you read real enterprise repositories — not just tutorial snippets with hard-coded names.
The classic Main method pattern you see here is still common in batch jobs, migration utilities, and Windows services even when newer templates use top-level statements.
Understanding the topic
Key concepts
- Entry point: Main method or top-level statements — execution begins here.
- Namespaces organize types and prevent naming collisions across assemblies.
- using directives import namespaces; global usings apply solution-wide.
- Assembly output: .dll for libraries, .exe (app host) for console apps.
- Command-line args arrive as string[] args; exit codes signal success (0) or failure (non-zero).
- File-scoped namespace reduces indentation: namespace Foo.Bar;
flowchart TDStart([Main Entry]) --> Init[Initialize]Init --> Logic[Business Logic]Logic --> Output[Console Output]Output --> End([Exit Code])
Step-by-step explanation
- Write source in .cs files; one project compiles all files into one assembly by default.
- dotnet build invokes Roslyn; errors appear with file and line numbers.
- dotnet run builds (if needed) and launches the app host with your entry point.
- Args pass from shell to Main/top-level as string[] args.
- Return int from Main or Environment.Exit(code) for scripting integration.
- Debug in IDE with breakpoints — F5 starts with debugger attached.
Practical code example
Classic Main vs top-level — both valid in .NET 8; enterprises often use explicit Program class for ASP.NET Core:
namespace TechLearningPro.FirstProgram;public static class Program{public static int Main(string[] args){if (args.Length == 0){Console.Error.WriteLine("Usage: FirstProgram <name>");return 1;}var greeting = GreetingService.Create(args[0]);Console.WriteLine(greeting);return 0;}}file static class GreetingService{public static string Create(string name) =>quot;Hello, {name}! Welcome to TechLearningPRO C#.";}
Output
Usage: FirstProgram <name>
Line-by-line code explanation
public static class Programholds the application entry point in many enterprise solutions.public static int Main(string[] args)receives command-line arguments and returns an exit code to the operating system.if (args.Length == 0)validates that the user supplied required input before continuing.Console.Error.WriteLine(...)writes the usage message to the error stream — the right channel for CLI tools.return 1signals failure to scripts and CI pipelines that check exit codes.GreetingService.Create(args[0])delegates formatting logic to a helper instead of bloatingMain.Console.WriteLine(greeting)prints the successful result to standard output.return 0tells the shell the program completed successfully.file static class GreetingServicekeeps the helper private to this source file (C# 11+).$"Hello, {name}! Welcome..."builds the greeting with string interpolation.
Key takeaway: file static class (C# 11+) keeps helpers private to the file. Return 1 on validation failure — scripts and CI detect non-zero exits.
Real-world use
Where you'll use this in production
- CLI migration tools run in Azure DevOps with exit codes gating deployment.
- Desktop app hosts still use explicit Main for single-threaded apartment (STA) flags.
- Microservice console workers process queue messages as generic host apps.
- Interview coding rounds often start with stdin/stdout console problems.
Best practices
- Use meaningful namespace names matching folder structure (TechLearningPro.Billing).
- Validate args early; print usage to Console.Error.
- Prefer top-level for learning scripts; refactor to classes as logic grows.
- Keep Main thin — delegate to injectable services in real apps.
- Document expected args in README and --help output.
Common mistakes
- Forgetting static on Main — compiler error CS5001.
- Wrong namespace causing type not found in other files.
- Running .dll directly without dotnet exec on wrong runtime.
- Mixing top-level statements in multiple files — only one file allowed.
Advanced interview questions
Q1BeginnerWhat is the entry point of a C# application?
Q2BeginnerWhat does return 0 from Main signify?
Q3IntermediateTop-level statements vs Main — when use each?
Q4IntermediateHow are command-line arguments passed?
Q5AdvancedTrace compilation from .cs to running process.
Summary
C# programs start at Main or top-level statements in an executable project. Namespaces and usings organize code; file-scoped namespaces reduce noise. dotnet build and dotnet run are your daily compile-run loop. Exit codes and stderr matter for CLI tools and CI pipelines. Next: variables, types, and the foundation of all C# logic.