C# Programming Tutorial 0/45 lessons ~6 min read Lesson 3

    Your First C# Program

    Every C# journey starts with a small program that compiles, runs, and prints output.

    Course progress0%
    Focus
    10 guided sections
    Practice signal
    Examples included
    Career prep
    Interview Q&A included

    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;
    text
    flowchart TD
    Start([Main Entry]) --> Init[Initialize]
    Init --> Logic[Business Logic]
    Logic --> Output[Console Output]
    Output --> End([Exit Code])

    Step-by-step explanation

    1. Write source in .cs files; one project compiles all files into one assembly by default.
    2. dotnet build invokes Roslyn; errors appear with file and line numbers.
    3. dotnet run builds (if needed) and launches the app host with your entry point.
    4. Args pass from shell to Main/top-level as string[] args.
    5. Return int from Main or Environment.Exit(code) for scripting integration.
    6. 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:

    csharp
    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 Program holds 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 1 signals failure to scripts and CI pipelines that check exit codes.
    • GreetingService.Create(args[0]) delegates formatting logic to a helper instead of bloating Main.
    • Console.WriteLine(greeting) prints the successful result to standard output.
    • return 0 tells the shell the program completed successfully.
    • file static class GreetingService keeps 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?
    Main method or top-level statements; the runtime calls it after assembly load.
    Q2BeginnerWhat does return 0 from Main signify?
    Success convention for operating systems and shell scripts.
    Q3IntermediateTop-level statements vs Main — when use each?
    Top-level for small tools; explicit Main/Program class for larger apps, testing, and STA configuration.
    Q4IntermediateHow are command-line arguments passed?
    As string[] args to Main; index 0 is first argument after executable name.
    Q5AdvancedTrace compilation from .cs to running process.
    Roslyn → IL in assembly → CLR loader → JIT → entry point invocation → managed execution on thread pool main thread.

    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.

    Ready to mark this lesson complete?Track your journey across the entire course.