Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
34 commits
Select commit Hold shift + click to select a range
a68e021
Revise index
BillWagner Mar 4, 2026
f5c8909
Move + revise namespaces.md
BillWagner Mar 4, 2026
dce22f7
Move + modernize namespace snippets
BillWagner Mar 4, 2026
1cbb2ae
Create new preprocessor-directives.md
BillWagner Mar 4, 2026
920840e
Create organizing-programs.md
BillWagner Mar 4, 2026
23fed87
Content edit.
BillWagner Mar 5, 2026
a0a5bbb
copy edit.
BillWagner Mar 5, 2026
d780ffe
Apply suggestions from code review
BillWagner Mar 5, 2026
8863882
one more formatting bit
BillWagner Mar 5, 2026
8a13590
Read-through and update
BillWagner Mar 6, 2026
aec74be
Major review of the index
BillWagner Mar 11, 2026
08ade05
Major edit on namespaces
BillWagner Mar 11, 2026
f66c682
build errors
BillWagner Mar 11, 2026
298e01c
major edit pass on preprocessor
BillWagner Mar 13, 2026
65cd84d
edit pass
BillWagner Mar 13, 2026
88a48be
Simplify the `Main` article
BillWagner Mar 13, 2026
55cda2e
Fix links
BillWagner Mar 13, 2026
70b50a8
Fix up samples
BillWagner Mar 13, 2026
536097e
remove snippets no longer needed
BillWagner Mar 13, 2026
7bdb76e
fix build
BillWagner Mar 13, 2026
bbf8cff
Revert "fix build"
BillWagner Mar 13, 2026
acc5dba
Revert "remove snippets no longer needed"
BillWagner Mar 13, 2026
829dae5
remove only some files.
BillWagner Mar 13, 2026
76d124a
Update edited articles per templates
BillWagner Mar 16, 2026
ac29a01
Update docs/csharp/fundamentals/program-structure/index.md
BillWagner Mar 19, 2026
9166ed2
Update docs/csharp/fundamentals/program-structure/namespaces.md
BillWagner Mar 19, 2026
77d18d9
Update docs/csharp/fundamentals/program-structure/program-organizatio…
BillWagner Mar 19, 2026
8d4d2aa
Update docs/csharp/fundamentals/program-structure/program-organizatio…
BillWagner Mar 19, 2026
99df55e
Update docs/csharp/fundamentals/program-structure/program-organizatio…
BillWagner Mar 19, 2026
62a86d0
Update docs/csharp/fundamentals/program-structure/main-command-line.md
BillWagner Mar 19, 2026
c23f607
Update docs/csharp/fundamentals/program-structure/top-level-statement…
BillWagner Mar 19, 2026
58b347a
Update docs/csharp/fundamentals/program-structure/top-level-statement…
BillWagner Mar 19, 2026
80df4b9
respond to feedback.
BillWagner Mar 19, 2026
e09c0e3
Add necessary file
BillWagner Mar 19, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4,218 changes: 2,111 additions & 2,107 deletions .openpublishing.redirection.csharp.json

Large diffs are not rendered by default.

1 change: 1 addition & 0 deletions docfx.json
Original file line number Diff line number Diff line change
Expand Up @@ -252,6 +252,7 @@
"docs/core/unmanaged-api/**/*.md": "reference",
"docs/core/whats-new/**/*.md": "whats-new",
"docs/csharp/advanced-topics/interface-implementation/**.md": "tutorial",
"docs/csharp/fundamentals/program-structure/**.md": "concept-article",
"docs/csharp/getting-started/**/*.md": "overview",
"docs/csharp/how-to/**/*.md": "how-to",
"docs/csharp/language-reference/**/*.md": "language-reference",
Expand Down
2 changes: 1 addition & 1 deletion docs/core/compatibility/sdk/6.0/csharp-template-code.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ Starting in .NET 6, the project templates that ship with the .NET SDK use the la
- [File-scoped namespaces](https://github.com/dotnet/csharplang/blob/main/proposals/csharp-10.0/file-scoped-namespaces.md)
- [Target-typed new expressions](/dotnet/csharp/language-reference/proposals/csharp-9.0/target-typed-new)
- [Nullable reference types](../../../../csharp/nullable-references.md)
- [Async Main return values](../../../../csharp/fundamentals/program-structure/main-command-line.md#async-main-return-values)
- [Async Main return values](../../../../csharp/fundamentals/program-structure/main-command-line.md#main-return-values)

Some of the latest C# language features are not supported by previous target frameworks, so you might experience issues in the following scenarios:

Expand Down
2 changes: 1 addition & 1 deletion docs/core/tutorials/top-level-templates.md
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,7 @@ The features that make the new program simpler are *top-level statements*, *glob

The term [*top-level statements*](../../csharp/fundamentals/program-structure/top-level-statements.md) means the compiler generates the class and method elements for your main program. The compiler declares the generated class and entry point method in the global namespace. Look at the code for the new application and imagine that it contains the statements inside the `Main` method generated by earlier templates, but in the global namespace.

Add more statements to the program, just as you add statements to your `Main` method in the traditional style. [Access `args` (command-line arguments)](../../csharp/fundamentals/program-structure/top-level-statements.md#args), [use `await`](../../csharp/fundamentals/program-structure/top-level-statements.md#await), and [set the exit code](../../csharp/fundamentals/program-structure/top-level-statements.md#exit-code-for-the-process). You can even add functions. The compiler creates them as local functions nested inside the generated entry point method. Local functions can't include any access modifiers (for example, `public` or `protected`).
Add more statements to the program, just as you add statements to your `Main` method in the traditional style. [Access `args` (command-line arguments)](../../csharp/fundamentals/program-structure/top-level-statements.md#args), [use `await`](../../csharp/fundamentals/program-structure/top-level-statements.md#await-and-exit-code), and [set the exit code](../../csharp/fundamentals/program-structure/top-level-statements.md#await-and-exit-code). You can even add functions. The compiler creates them as local functions nested inside the generated entry point method. Local functions can't include any access modifiers (for example, `public` or `protected`).

Both top-level statements and [implicit `using` directives](#implicit-using-directives) simplify the code that makes up your application. To follow an existing tutorial, add any new statements to the *Program.cs* file generated by the template. Imagine that the statements you write are between the open and closing braces in the `Main` method in the instructions of the tutorial.

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -118,7 +118,7 @@ static async Task Main()
}
```

The updated `Main` method is now considered an [Async main](../fundamentals/program-structure/main-command-line.md#async-main-return-values), which allows for an asynchronous entry point into the executable. It writes a few instructional messages to the console, then declares a <xref:System.Threading.Tasks.Task> instance named `cancelTask`, which will read console key strokes. If the <kbd>Enter</kbd> key is pressed, a call to <xref:System.Threading.CancellationTokenSource.Cancel?displayProperty=nameWithType> is made. This will signal cancellation. Next, the `sumPageSizesTask` variable is assigned from the `SumPageSizesAsync` method. Both tasks are then passed to <xref:System.Threading.Tasks.Task.WhenAny(System.Threading.Tasks.Task[])?displayProperty=nameWithType>, which will continue when any of the two tasks have completed.
The updated `Main` method is now considered an [Async main](../fundamentals/program-structure/main-command-line.md#main-return-values), which allows for an asynchronous entry point into the executable. It writes a few instructional messages to the console, then declares a <xref:System.Threading.Tasks.Task> instance named `cancelTask`, which will read console key strokes. If the <kbd>Enter</kbd> key is pressed, a call to <xref:System.Threading.CancellationTokenSource.Cancel?displayProperty=nameWithType> is made. This will signal cancellation. Next, the `sumPageSizesTask` variable is assigned from the `SumPageSizesAsync` method. Both tasks are then passed to <xref:System.Threading.Tasks.Task.WhenAny(System.Threading.Tasks.Task[])?displayProperty=nameWithType>, which will continue when any of the two tasks have completed.

The next block of code ensures that the application doesn't exit until the cancellation has been processed. If the first task to complete is the `cancelTask`, the `sumPageSizeTask` is awaited. If it was cancelled, when awaited it throws a <xref:System.Threading.Tasks.TaskCanceledException?displayProperty=nameWithType>. The block catches that exception, and prints a message.

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -82,7 +82,7 @@ The main entry point into the console application is the `Main` method. Replace
static Task Main() => SumPageSizesAsync();
```

The updated `Main` method is now considered an [Async main](../fundamentals/program-structure/main-command-line.md#async-main-return-values), which allows for an asynchronous entry point into the executable. It is expressed as a call to `SumPageSizesAsync`.
The updated `Main` method is now considered an [Async main](../fundamentals/program-structure/main-command-line.md#main-return-values), which allows for an asynchronous entry point into the executable. It is expressed as a call to `SumPageSizesAsync`.

## Create the asynchronous sum page sizes method

Expand Down
124 changes: 87 additions & 37 deletions docs/csharp/fundamentals/program-structure/index.md
Original file line number Diff line number Diff line change
@@ -1,73 +1,123 @@
---
title: "General Structure of a Program"
description: Learn about the structure of a C# program by using a skeleton program that contains all the required elements for a program.
ms.date: 06/20/2025
helpviewer_keywords:
- "C# language, program structure"
title: "General structure of a C# program"
description: Learn how C# programs are structured, including the choice between file-based and project-based apps, top-level statements and Main method entry points, and the building blocks that make up every program.
ms.date: 03/16/2026
ms.topic: concept-article
ai-usage: ai-assisted

#customer intent: As a C# developer, I want to understand how C# programs are structured so that I can choose the right application style and organize my code effectively.

---
# General Structure of a C# Program
# General structure of a C# program

C# programs consist of one or more files. Each file contains zero or more namespaces. A namespace contains types such as classes, structs, interfaces, enumerations, and delegates, or other namespaces. The following example is the skeleton of a C# program that contains all of these elements.
> [!TIP]
> **New to developing software?** Start with the [Get started](../../tour-of-csharp/tutorials/index.md) tutorials first. They walk you through writing your first C# programs before you learn about program structure.
>
> **Experienced in another language?** You might want to skim the [Get started](../../tour-of-csharp/tutorials/index.md) section for C#-specific syntax, then come back here.

:::code language="csharp" source="snippets/toplevel-structure/Program.cs":::
You build C# programs from these core building blocks: namespaces organize your types, types (classes, structs, interfaces, enums, and delegates) define behavior and data, and statements and expressions perform work at run time. The way you structure the entry point depends on which application style you choose.

The preceding example uses [*top-level statements*](top-level-statements.md) for the program's entry point. Only one file can have top-level statements. The program's entry point is the first text line of program text in that file. In this case, it's the `Console.WriteLine("Hello world!");`.
You can also create a static method named [`Main`](main-command-line.md) as the program's entry point, as shown in the following example:
## Choosing your application style

:::code language="csharp" source="snippets/structure/Program.cs":::
When you create a C# program, make two independent choices about how to structure it:

In that case the program starts in the opening brace of `Main` method, which is `Console.WriteLine("Hello world!");`
- **File-based or project-based?**
- A file-based app runs from a single `.cs` file with no project file.
- A project-based app uses a `.csproj` file and can span multiple source files.
- **Top-level statements or `Main` method?**
- Top-level statements let you write executable code directly at the top of a file.
- A `Main` method wraps the entry point in an explicit static method.

## Building and running C# programs
Both project-based apps and file-based apps support either entry-point style.

C# is a *compiled* language. In most C# programs, you use the [`dotnet build`](../../../core/tools/dotnet-build.md) command to compile a group of source files into a binary package. Then, you use the [`dotnet run`](../../../core/tools/dotnet-run.md) command to run the program. (You can simplify this process because `dotnet run` compiles the program before running it if necessary.) These tools support a rich language of configuration options and command-line switches. The `dotnet` command line interface (CLI), which is included in the .NET SDK, provides many [tools](../../../core/tools/index.md) to generate and modify C# files.
### File-based apps vs. project-based apps
Comment thread
BillWagner marked this conversation as resolved.

Beginning with C# 14 and .NET 10, you can create *file-based apps*, which simplifies building and running C# programs. You use the `dotnet run` command to run a program contained in a single `*.cs` file. For example, if the following snippet is stored in a file named `hello-world.cs`, you can run it by typing `dotnet run hello-world.cs`:
Starting with C# 14 and .NET 10, *file-based apps* let you run a program contained in a single `*.cs` file without a project file. Store the following code in a file named `hello-world.cs` and run it with `dotnet run hello-world.cs` or `dotnet hello-world.cs`:

:::code language="csharp" source="./snippets/file-based-program/hello-world.cs":::

The first line of the program contains the `#!` sequence for Unix shells. The location of the `dotnet` CLI can vary on different distributions. On any Unix system, if you set the *execute* (`+x`) permission on a C# file, you can run the C# file from the command line:
> [!NOTE]
> The `#!` line enables Unix shells to run the file directly. On any Unix system, set the *execute* (`+x`) permission and run the file from the command line.

File-based apps support all C# syntax and can use [preprocessor directives](../../language-reference/preprocessor-directives.md#file-based-apps) to configure the build system. Use file-based apps for small command-line utilities, prototypes, and experiments. A file-based app consists of a single file in a directory:

```
my-app/
└── hello-world.cs
```

```bash
./hello-world.cs
*Project-based apps* use a `.csproj` file and the [.NET CLI commands](../../../core/tools/index.md) `dotnet new`, `dotnet build`, and `dotnet run` workflow. Choose project-based apps when your program spans multiple files or needs fine-grained build configuration. A project-based app includes a project file alongside one or more source files:

```
my-app/
├── my-app.csproj
├── Program.cs
├── Models/
│ └── Person.cs
└── Services/
└── GreetingService.cs
```

The source for these programs must be a single file, but otherwise all C# syntax is valid. You can use file-based apps for small command-line utilities, prototypes, or other experiments. file-based apps allow [preprocessor directives](../../language-reference/preprocessor-directives.md#file-based-apps) that configure the build system.
If your file-based app grows, you can easily convert it to a project-based app. Run [`dotnet project convert`](../../../core/tools/dotnet-project-convert.md) to generate a project file from your existing source file.

If you know your app needs multiple source files from the start, begin with a project-based app. You avoid the conversion step and can organize your code into separate files right away.

### Top-level statements vs. `Main` method

By using [top-level statements](top-level-statements.md), you can write executable code directly in one file without wrapping it in a class and `Main` method. This style is the default when you create a new console app with `dotnet new console`. The following example shows a modern C# program that uses [top-level statements](top-level-statements.md):

:::code language="csharp" source="snippets/toplevel-structure/Program.cs":::

Only one file in a project can have top-level statements, and the entry point is the first line of program text in that file. As you build larger programs, you include more program elements.

You can also define an explicit static [`Main`](main-command-line.md) method as the program's entry point:
Comment thread
BillWagner marked this conversation as resolved.

:::code language="csharp" source="snippets/structure/Program.cs":::
Comment thread
BillWagner marked this conversation as resolved.

Both entry-point styles work with file-based and project-based apps. Both styles support the same features.

## Building and running C# programs

C# is a *compiled* language. For project-based apps, use the [`dotnet build`](../../../core/tools/dotnet-build.md) command to compile source files into a binary package. Use [`dotnet run`](../../../core/tools/dotnet-run.md) to build and run in one step. The `dotnet` CLI, included in the .NET SDK, provides many [tools](../../../core/tools/index.md) to create, build, and manage C# projects.

For file-based apps, `dotnet run hello-world.cs` compiles and runs the single file directly - no project file required.
Comment thread
BillWagner marked this conversation as resolved.

## Expressions and statements

C# programs are built using *expressions* and *statements*. Expressions produce a value, and statements perform an action:
If you followed the [Get started](../../tour-of-csharp/overview.md) tutorials, you already wrote expressions and statements. Every line of code you typed was one or the other (or both). Now let's define those terms.

An *expression* is a combination of values, variables, operators, and method calls that evaluate to a single value. Expressions produce a result and can be used wherever a value is expected. The following examples are expressions:
Expressions and statements are the fundamental building blocks of a C# program. An *expression* produces a value. A *statement* performs an action and typically ends in a semicolon.

The following are expressions:

- `42` (literal value)
- `x + y` (arithmetic operation)
- `Math.Max(a, b)` (method call)
- `Math.Max(a, b)` (method call that produces a value)
- `condition ? trueValue : falseValue` (conditional expression)
- `new Person("John")` (object creation)

A *statement* is a complete instruction that performs an action. Statements don't return values; instead, they control program flow, declare variables, or perform operations. The following examples are statements:
A *statement* performs an action. Statements control program flow, declare variables, or invoke operations. The following are statements:

- `int x = 42;` (declaration statement)
- `Console.WriteLine("Hello");` (expression statement - wraps a method call expression)
- `int x;` (declaration statement)
- `int x = 42;` (declaration statement with initialization)
- `Console.WriteLine("Hello");` (method call statement)
- `if (condition) { /* code */ }` (conditional statement)
- `return result;` (return statement)

The key distinction: expressions evaluate to values, while statements perform actions. Some constructs, like method calls, can be both. For example, `Math.Max(a, b)` is an expression when used in `int result = Math.Max(a, b);`, but becomes an expression statement when written alone as `Math.Max(a, b);`.
Statements often contain expressions, and expressions can nest inside other expressions. For example, the following declaration statement assigns `f` to the result of an addition expression. That addition expression adds the results of two method call expressions:

For detailed information about statements, see [Statements](../../programming-guide/statements-expressions-operators/statements.md). For information about expression-bodied members and other expression features, see [Expression-bodied members](../../programming-guide/statements-expressions-operators/expression-bodied-members.md).
```csharp
var maxResult = Math.Max(a, b) + Math.Max(c, d);
```
Comment thread
BillWagner marked this conversation as resolved.

## Related Sections
For detailed information about statements, see [Statements](../../programming-guide/statements-expressions-operators/statements.md). For information about expression-bodied members, see [Expression-bodied members](../../programming-guide/statements-expressions-operators/expression-bodied-members.md).

You learn about these program elements in the [types](../types/index.md) section of the fundamentals guide:
## Related content

- [Classes](../types/classes.md)
- [Structs](../../language-reference/builtin-types/struct.md)
- [Namespaces](../types/namespaces.md)
- [Interfaces](../types/interfaces.md)
- [Classes](../types/classes.md)
- [Structs](../../language-reference/builtin-types/struct.md)
- [Namespaces](namespaces.md)
- [Interfaces](../types/interfaces.md)
- [Enums](../../language-reference/builtin-types/enum.md)
- [Delegates](../../delegates-overview.md)

## C# Language Specification

For more information, see [Basic concepts](~/_csharpstandard/standard/basic-concepts.md) in the [C# Language Specification](~/_csharpstandard/standard/README.md). The language specification is the definitive source for C# syntax and usage.
- [Basic concepts in the C# language specification](~/_csharpstandard/standard/basic-concepts.md)
Loading
Loading