-
Notifications
You must be signed in to change notification settings - Fork 6.1k
[Everyday C#] - Program structure: namespaces + preprocessor directives #52082
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Open
BillWagner
wants to merge
13
commits into
dotnet:main
Choose a base branch
from
BillWagner:program-structure
base: main
Could not load branches
Branch not found: {{ refName }}
Loading
Could not load tags
Nothing to show
Loading
Are you sure you want to change the base?
Some commits from the old base branch may be removed from the timeline,
and old review comments may become outdated.
Open
Changes from all commits
Commits
Show all changes
13 commits
Select commit
Hold shift + click to select a range
3144cc8
Revise index
BillWagner 65664c0
Move + revise namespaces.md
BillWagner e2a2316
Move + modernize namespace snippets
BillWagner 28927c1
Create new preprocessor-directives.md
BillWagner 5cc6a31
Create organizing-programs.md
BillWagner 1657e7c
Content edit.
BillWagner 4058ab3
copy edit.
BillWagner 04d5bbe
Apply suggestions from code review
BillWagner 04d2396
one more formatting bit
BillWagner c743944
Read-through and update
BillWagner 6743192
Major review of the index
BillWagner 4f1c329
Major edit on namespaces
BillWagner a46d93e
build errors
BillWagner File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
Large diffs are not rendered by default.
Oops, something went wrong.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,73 +1,126 @@ | ||
| --- | ||
| 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: | ||
| 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/11/2026 | ||
| ai-usage: ai-assisted | ||
| helpviewer_keywords: | ||
| - "C# language, program structure" | ||
| --- | ||
| # 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/overview.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/overview.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 | ||
|
|
||
| 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 | ||
| ``` | ||
|
|
||
| *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: | ||
|
|
||
| ```bash | ||
| ./hello-world.cs | ||
| ``` | ||
| my-app/ | ||
| ├── my-app.csproj | ||
| ├── Program.cs | ||
| ├── Models/ | ||
| │ └── Person.cs | ||
| └── Services/ | ||
| └── GreetingService.cs | ||
| ``` | ||
|
|
||
| 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. | ||
|
|
||
| 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. | ||
| ### 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: | ||
BillWagner marked this conversation as resolved.
Show resolved
Hide resolved
|
||
|
|
||
| :::code language="csharp" source="snippets/structure/Program.cs"::: | ||
BillWagner marked this conversation as resolved.
Show resolved
Hide 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. | ||
BillWagner marked this conversation as resolved.
Show resolved
Hide 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. | ||
|
|
||
| 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. | ||
|
|
||
| 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: | ||
| 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 f = Math.Max(a, b) + Math.Max(c, d); | ||
| ``` | ||
|
|
||
| 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). | ||
|
|
||
| ## Related Sections | ||
| ## Related sections | ||
|
|
||
| You learn about these program elements in the [types](../types/index.md) section of the fundamentals guide: | ||
| Learn about these program elements in the [types](../types/index.md) section of the fundamentals guide: | ||
|
|
||
| - [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 | ||
|
|
||
| ## 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. | ||
101 changes: 101 additions & 0 deletions
101
docs/csharp/fundamentals/program-structure/namespaces.md
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,101 @@ | ||
| --- | ||
| title: "Namespaces and using directives" | ||
| description: Learn how to organize C# code with namespaces, file-scoped namespace declarations, global usings, static usings, and type aliases. | ||
| ms.date: 03/04/2026 | ||
| ai-usage: ai-assisted | ||
| helpviewer_keywords: | ||
| - "C# language, namespaces" | ||
| - "namespaces [C#]" | ||
| - "using directive [C#]" | ||
| - "global using [C#]" | ||
| - "file-scoped namespace [C#]" | ||
| --- | ||
| # Namespaces and using directives | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This article weaves between namespaces and using directives. It would probably make more sense to fully explain namespaces and then move on to how using directives help you use namespaces. |
||
|
|
||
| > [!TIP] | ||
| > **New to developing software?** Start with the [Get started](../../tour-of-csharp/tutorials/index.md) tutorials first. They introduce namespaces and `using` directives as you write your first programs. | ||
| > | ||
| > **Experienced in another language?** Namespaces in C# work similarly to packages in Java or modules in Python. Skim ahead to the syntax you need. | ||
|
|
||
| Namespace declarations and `using` directives are two sides of the same coin. A namespace declaration puts your types into an organized structure. A namespace groups related types together and prevents naming collisions. A `using` directive lets your program consume those types by their simple names. You don't have to spell out the full namespace path at every use. | ||
|
|
||
| Every .NET type belongs to a namespace. For example, the `System` namespace contains fundamental types like `System.Console` and `System.Math`. The `System.Collections.Generic` namespace groups collection types like `List<T>` and `Dictionary<TKey, TValue>`. The `System.Threading.Tasks` namespace holds `Task` and `ValueTask<T>` for asynchronous programming. A single `using` directive for any of these namespaces lets you refer to all its types by their simple names. You write `List<T>` instead of `System.Collections.Generic.List<T>` everywhere you use it. | ||
|
|
||
| The following example shows how namespaces work together with `using` directives in a typical C# file: | ||
|
|
||
| :::code language="csharp" source="snippets/namespaces/Basics.cs" id="NamespaceBasics"::: | ||
|
|
||
| In the preceding sample, the `using` directive means you can use the <xref:System.Globalization.CultureInfo?displayProperty=nameWithType> by the name `CultureInfo` without specifying the full name of `System.Globalization.CultureInfo`. The `namespace` directive declares that the `Greeter` class is part of the `MyApp.Services` namespace. Its fully qualified name is `MyApp.Services.Greeter`. | ||
|
|
||
| ## Namespace declarations | ||
|
|
||
| A namespace declaration assigns your types to a named group. Every type you write should belong to a namespace. The namespace name typically mirrors the folder structure of your project. For example, types in a `Services/Payments` folder often belong to the `MyApp.Services.Payments` namespace. | ||
|
|
||
| Namespaces use the `.` operator to express hierarchy, such as `System.Collections.Generic`. The `global` namespace is the root namespace - `global::System` always refers to the .NET <xref:System> namespace. Namespace names must be valid C# [identifier names](../coding-style/identifier-names.md). | ||
|
|
||
| ### File-scoped namespaces | ||
|
|
||
| Use the *file-scoped* syntax when all types in a file belong to the same namespace. Add a semicolon after the namespace declaration, and it applies to the entire file. You don't need extra braces or indentation: | ||
|
|
||
| :::code language="csharp" source="snippets/namespaces/FileScopedExample.cs" id="FileScopedNamespace"::: | ||
|
|
||
| File-scoped namespaces reduce nesting and make files easier to read. You can only have one file-scoped namespace declaration per file. | ||
|
|
||
| > [!TIP] | ||
| > Use file-scoped namespaces in new code. Most .NET templates and code analyzers recommend this style. | ||
|
|
||
| ### Block-scoped namespaces | ||
|
|
||
| The older block-scoped syntax wraps all types in braces. This style is still valid but adds an extra level of indentation: | ||
|
|
||
| :::code language="csharp" source="snippets/namespaces/BlockScoped.cs" id="BlockScopedNamespace"::: | ||
|
|
||
| ## Using directives | ||
|
|
||
| Without a `using` directive, you must refer to every type by its *fully qualified name*, the complete namespace path plus the type name: | ||
|
|
||
| :::code language="csharp" source="snippets/namespaces/Basics.cs" id="FullyQualifiedName"::: | ||
|
|
||
| A `using` directive at the top of a file imports a namespace so you can use its types by their simple names: | ||
|
|
||
| :::code language="csharp" source="snippets/namespaces/Basics.cs" id="UsingDirective"::: | ||
|
|
||
| For more information, see the [`using` directive](../../language-reference/keywords/using-directive.md). | ||
|
|
||
| ### Global using directives | ||
|
|
||
| If you write the same `using` directives in every file, *global using* directives let you declare them once for your entire project. Place them in any file. Many teams create a dedicated `GlobalUsings.cs` file: | ||
|
|
||
| :::code language="csharp" source="snippets/namespaces/GlobalUsings.cs" id="GlobalUsings"::: | ||
|
|
||
| After declaring a global using, every file in the project can refer to types from that namespace by using simple names without an additional `using` directive. | ||
|
|
||
| ### Implicit usings | ||
|
|
||
| The .NET SDK automatically generates global using directives for the most common namespaces based on your project type. Enable implicit usings by setting `<ImplicitUsings>enable</ImplicitUsings>` in your project file. For example, a console app project automatically imports `System`, `System.Collections.Generic`, `System.IO`, `System.Linq`, `System.Threading`, and `System.Threading.Tasks`. The current SDK enables `ImplicitUsings` when you create a new project by using `dotnet new`. | ||
|
|
||
| For more information, see [Implicit using directives](../../../core/project-sdk/overview.md#implicit-using-directives). | ||
|
|
||
| ### Static using directives | ||
|
|
||
| A `static using` directive imports the static members of a type so you can call them without the type name prefix: | ||
|
|
||
| :::code language="csharp" source="snippets/namespaces/StaticUsing.cs" id="StaticUsing"::: | ||
|
|
||
| Static usings work well for utility classes like <xref:System.Math> and <xref:System.Console> that you call frequently. | ||
|
|
||
| ### Type and namespace aliases | ||
|
|
||
| A `using` alias creates a shorthand name for a type or namespace. Aliases are useful for long generic types, resolving naming conflicts, and improving readability: | ||
|
|
||
| :::code language="csharp" source="snippets/namespaces/Aliases.cs" id="TypeAlias"::: | ||
|
|
||
| Starting with C# 12, you can alias any type, including tuples and pointer types: | ||
|
|
||
| :::code language="csharp" source="snippets/namespaces/TupleAlias.cs" id="AnyTypeAlias"::: | ||
|
|
||
| For more advanced scenarios where two assemblies define the same fully qualified type name, use [extern alias](../../language-reference/keywords/extern-alias.md) to disambiguate between them. | ||
|
|
||
| ## C# language specification | ||
|
|
||
| For more information, see the [Namespaces](~/_csharpstandard/standard/namespaces.md) section of the [C# language specification](~/_csharpstandard/standard/README.md). | ||
Oops, something went wrong.
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.