Hello World and Project Structure
Writing "Hello, World!" in C# has gotten dramatically simpler over the years. Early C# required an explicit namespace, class, and a static void Main(string[] args) method just to print one line. Since C# 9 (2020) and the top-level statements feature, a console app's entire logic can live directly in Program.cs with no boilerplate wrapper, while the compiler generates the class and Main method behind the scenes. Understanding both the modern minimal form and what it compiles down to is essential, because most real-world codebases still mix both styles depending on their age and conventions.
Cricket analogy: Early cricket broadcasts required a full studio setup before showing a single ball, but modern mobile apps stream one delivery instantly with no setup screen, yet commentators still need to understand the full broadcast rig for older archived matches.
Anatomy of a Console Project
Running dotnet new console produces two key files: Program.cs, containing your executable code, and a .csproj (MSBuild project) file, an XML document describing the project's target framework, output type, and package references. The .csproj is deliberately terse in modern .NET — the SDK-style project format infers sensible defaults (like including all .cs files in the folder automatically) so you rarely need to hand-edit it for a simple app.
Cricket analogy: dotnet new console is like a cricket academy issuing a recruit both a kit bag (Program.cs, where the action happens) and a registration form (.csproj) describing league and division, most fields auto-filled by default.
Top-Level Statements vs. Explicit Main
Top-level statements are syntactic sugar: the compiler still generates an internal Program class with a Main method, but you write only the statements that would go inside it, directly at the top of the file. This is ideal for scripts, small tools, and tutorials. Larger applications, or ones needing an explicitly named entry-point class (for example, to reference Program from a test project), often still use the traditional explicit form.
Cricket analogy: Top-level statements are like a street-cricket match skipping the formal toss ceremony but still implicitly following the same rules underneath, while an international Test match keeps the explicit toss for official record-keeping.
// --- Modern: Program.cs using top-level statements (C# 9+) ---
string name = args.Length > 0 ? args[0] : "World";
Console.WriteLine($"Hello, {name}!");
// --- Equivalent traditional form, what the compiler generates for you ---
// using System;
//
// namespace HelloApp
// {
// internal class Program
// {
// private static void Main(string[] args)
// {
// string name = args.Length > 0 ? args[0] : "World";
// Console.WriteLine($"Hello, {name}!");
// }
// }
// }A minimal SDK-style .csproj for a console app can be as short as: <Project Sdk="Microsoft.NET.Sdk"><PropertyGroup><OutputType>Exe</OutputType><TargetFramework>net8.0</TargetFramework><ImplicitUsings>enable</ImplicitUsings><Nullable>enable</Nullable></PropertyGroup></Project>. Compare this to the hundreds of lines a classic .NET Framework .csproj required, listing every source file explicitly.
Only one file in a project may contain top-level statements — the compiler needs a single unambiguous entry point. Mixing top-level statements in Program.cs with another file that also declares a static void Main will produce a compile error.
- A console project consists mainly of Program.cs (code) and a .csproj (build/dependency metadata).
- Top-level statements (C# 9+) let you skip the explicit namespace/class/Main boilerplate for simple entry points.
- The compiler still generates a hidden Program class and Main method under top-level statements — it's pure syntax sugar.
- SDK-style .csproj files are terse: they implicitly include all .cs files in the folder rather than listing each one.
<ImplicitUsings>enable</ImplicitUsings>and<Nullable>enable</Nullable>are common modern project defaults set in the .csproj.- Only one file per project may use top-level statements, since there can be exactly one program entry point.
Practice what you learned
1. Since which C# version have top-level statements been available?
2. What does the compiler generate behind the scenes when you use top-level statements?
3. Which file typically defines a console project's target framework and output type?
4. How many files in a single project may contain top-level statements?
5. In an SDK-style .csproj, how are .cs source files typically included in the build?
Was this page helpful?
You May Also Like
Setting Up .NET
A practical walkthrough of installing the .NET SDK, choosing an editor, and understanding the dotnet CLI toolchain that underlies all C# development.
What Is C#?
An overview of C# as a modern, type-safe, object-oriented language built for the .NET platform, covering its history, design goals, and where it fits today.
Namespaces and Assemblies
Learn how C# namespaces organize code logically while assemblies (.dll/.exe) are the physical, deployable units the .NET runtime actually loads.
Variables and Data Types
Covers how C# declares and initializes variables, its built-in value and reference types, type inference with var, and the difference between static and dynamic typing.
Related Reading
Related Study Notes in Programming
Browse all study notesApache Spark Study Notes
Programming · 30 topics
ProgrammingApache Flink Study Notes
Programming · 30 topics
ProgrammingHadoop Study Notes
Programming · 30 topics
ProgrammingSnowflake Study Notes
Programming · 30 topics
ProgrammingApache Airflow Study Notes
Programming · 30 topics
Programmingdbt (Data Build Tool) Study Notes
Programming · 30 topics