Skip to content

Commit 4fafcf7

Browse files
BillWagnerCopilotgewarren
authored
Clarify that the file modifier isn't an access modifier, it's a different type of modifier. (#50589)
* Fix technical errors on the `file` modifier The `file` modifier isn't classified as an access modifier. It's a modifier that can't be combined with any other access modifier, and can only be applied to top-level types. * Do a full edit pass * Fix lint issues * Apply suggestions from code review Co-authored-by: Copilot <[email protected]> * Fix snippets, update code * fix snippet build, update some links * lint * Update docs/csharp/fundamentals/program-structure/main-command-line.md Co-authored-by: Genevieve Warren <[email protected]> --------- Co-authored-by: Copilot <[email protected]> Co-authored-by: Genevieve Warren <[email protected]>
1 parent f32477e commit 4fafcf7

File tree

11 files changed

+138
-151
lines changed

11 files changed

+138
-151
lines changed

docs/csharp/fundamentals/program-structure/main-command-line.md

Lines changed: 41 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
---
22
title: "Main() and command-line arguments"
33
description: Learn about Main() and command-line arguments. The 'Main' method is the entry point of an executable program.
4-
ms.date: 06/23/2025
4+
ms.date: 12/15/2025
55
f1_keywords:
66
- "main_CSharpKeyword"
77
- "Main"
@@ -14,27 +14,27 @@ helpviewer_keywords:
1414
---
1515
# Main() and command-line arguments
1616

17-
The `Main` method is the entry point of a C# application. When the application is started, the `Main` method is the first method that is invoked.
17+
The runtime calls the `Main` method when you start a C# application. The `Main` method is the entry point of a C# application.
1818

19-
There can only be one entry point in a C# program. If you have more than one class that has a `Main` method, you must compile your program with the **StartupObject** compiler option to specify which `Main` method to use as the entry point. For more information, see [**StartupObject** (C# Compiler Options)](../../language-reference/compiler-options/advanced.md#startupobject). The following example displays the number of command line arguments as its first action:
19+
A C# program can have only one entry point. If you have more than one class with a `Main` method, you must use the **StartupObject** compiler option when you compile your program to specify which `Main` method serves as the entry point. For more information, see [**StartupObject** (C# Compiler Options)](../../language-reference/compiler-options/advanced.md#startupobject). The following example displays the number of command line arguments as its first action:
2020

2121
:::code language="csharp" source="snippets/main-command-line/TestClass.cs":::
2222

23-
You can also use top-level statements in one file as the entry point for your application. Just as the `Main` method, top-level statements can also [return values](#main-return-values) and access [command-line arguments](#command-line-arguments). For more information, see [Top-level statements](top-level-statements.md). The following example uses a `foreach` loop to display the command-line arguments using the `args` variable, and at the end of the program returns a success code (`0`):
23+
You can also use top-level statements in one file as the entry point for your application. Like the `Main` method, top-level statements can [return values](#main-return-values) and access [command-line arguments](#command-line-arguments). For more information, see [Top-level statements](top-level-statements.md). The following example uses a `foreach` loop to display the command-line arguments by using the `args` variable, and at the end of the program returns a success code (`0`):
2424

2525
:::code language="csharp" source="snippets/top-level-statements-1/Program.cs":::
2626

27-
Beginning with C# 14, programs can be [*file-based apps*](./index.md#building-and-running-c-programs), where a single file contains the program. You run *file-based apps* with the command `dotnet run <file.cs>`, or using the `#!/usr/local/share/dotnet/dotnet run` directive as the first line (unix shells only).
27+
Beginning with C# 14, programs can be [*file-based apps*](./index.md#building-and-running-c-programs), where a single file contains the program. You run *file-based apps* by using the command `dotnet <file.cs>`, or by using the `#!/usr/bin/env dotnet run` directive as the first line (Unix shells only).
2828

2929
## Overview
3030

31-
- The `Main` method is the entry point of an executable program; it's where the program control starts and ends.
32-
- `Main` must be declared inside a class or struct. The enclosing `class` can be `static`.
31+
- The `Main` method is the entry point of an executable program. It's where the program control starts and ends.
32+
- You must declare `Main` inside a class or struct. The enclosing `class` can be `static`.
3333
- `Main` must be [`static`](../../language-reference/keywords/static.md).
34-
- `Main` can have any [access modifier](../../programming-guide/classes-and-structs/access-modifiers.md) (except `file`).
35-
- `Main` can either have a `void`, `int`, `Task`, or `Task<int>` return type.
34+
- `Main` can have any [access modifier](../../programming-guide/classes-and-structs/access-modifiers.md).
35+
- `Main` can return `void`, `int`, `Task`, or `Task<int>`.
3636
- If and only if `Main` returns a `Task` or `Task<int>`, the declaration of `Main` can include the [`async`](../../language-reference/keywords/async.md) modifier. This rule specifically excludes an `async void Main` method.
37-
- The `Main` method can be declared with or without a `string[]` parameter that contains command-line arguments. When using Visual Studio to create Windows applications, you can add the parameter manually or else use the <xref:System.Environment.GetCommandLineArgs> method to obtain the command-line arguments. Parameters are read as zero-indexed command-line arguments. Unlike C and C++, the name of the program isn't treated as the first command-line argument in the `args` array, but it's the first element of the <xref:System.Environment.GetCommandLineArgs> method.
37+
- You can declare the `Main` method with or without a `string[]` parameter that contains command-line arguments. When using Visual Studio to create Windows applications, you can add the parameter manually or else use the <xref:System.Environment.GetCommandLineArgs> method to obtain the command-line arguments. Parameters are zero-indexed command-line arguments. Unlike C and C++, the name of the program isn't treated as the first command-line argument in the `args` array, but it's the first element of the <xref:System.Environment.GetCommandLineArgs> method.
3838

3939
The following list shows the most common `Main` declarations:
4040

@@ -49,10 +49,10 @@ static async Task Main(string[] args) { }
4949
static async Task<int> Main(string[] args) { }
5050
```
5151

52-
The preceding examples don't specify an access modifier, so they're implicitly `private` by default. It's possible to specify any explicit access modifier.
52+
The preceding examples don't specify an access modifier, so they're implicitly `private` by default. You can specify any explicit access modifier.
5353

5454
> [!TIP]
55-
> The addition of `async` and `Task`, `Task<int>` return types simplifies program code when console applications need to start and `await` asynchronous operations in `Main`.
55+
> By using `async` and `Task` or `Task<int>` return types, you simplify program code when console applications need to start and `await` asynchronous operations in `Main`.
5656
5757
## Main() return values
5858

@@ -86,13 +86,13 @@ Create a new application by running `dotnet new console`. Modify the `Main` meth
8686

8787
Remember to save this program as *MainReturnValTest.cs*.
8888

89-
When a program is executed in Windows, any value returned from the `Main` function is stored in an environment variable. This environment variable can be retrieved using `ERRORLEVEL` from a batch file, or `$LastExitCode` from PowerShell.
89+
When you execute a program in Windows, the system stores any value returned from the `Main` function in an environment variable. You can retrieve this environment variable by using `ERRORLEVEL` from a batch file, or `$LastExitCode` from PowerShell.
9090

91-
You can build the application using the [dotnet CLI](../../../core/tools/dotnet.md) `dotnet build` command.
91+
You can build the application by using the [dotnet CLI](../../../core/tools/dotnet.md) `dotnet build` command.
9292

9393
Next, create a PowerShell script to run the application and display the result. Paste the following code into a text file and save it as `test.ps1` in the folder that contains the project. Run the PowerShell script by typing `test.ps1` at the PowerShell prompt.
9494

95-
Because the code returns zero, the batch file reports success. However, if you change MainReturnValTest.cs to return a non-zero value and then recompile the program, subsequent execution of the PowerShell script reports failure.
95+
Because the code returns zero, the batch file reports success. However, if you change MainReturnValTest.cs to return a nonzero value and then recompile the program, subsequent execution of the PowerShell script reports failure.
9696

9797
```powershell
9898
dotnet run
@@ -116,21 +116,21 @@ When you declare an `async` return value for `Main`, the compiler generates the
116116

117117
:::code language="csharp" source="snippets/main-arguments/Program.cs" id="AsyncMain":::
118118

119-
In both examples main body of the program is within the body of `AsyncConsoleWork()` method.
119+
In both examples, the main body of the program is within the body of the `AsyncConsoleWork()` method.
120120

121121
An advantage of declaring `Main` as `async` is that the compiler always generates the correct code.
122122

123123
When the application entry point returns a `Task` or `Task<int>`, the compiler generates a new entry point that calls the entry point method declared in the application code. Assuming that this entry point is called `$GeneratedMain`, the compiler generates the following code for these entry points:
124124

125-
- `static Task Main()` results in the compiler emitting the equivalent of `private static void $GeneratedMain() => Main().GetAwaiter().GetResult();`
126-
- `static Task Main(string[])` results in the compiler emitting the equivalent of `private static void $GeneratedMain(string[] args) => Main(args).GetAwaiter().GetResult();`
127-
- `static Task<int> Main()` results in the compiler emitting the equivalent of `private static int $GeneratedMain() => Main().GetAwaiter().GetResult();`
128-
- `static Task<int> Main(string[])` results in the compiler emitting the equivalent of `private static int $GeneratedMain(string[] args) => Main(args).GetAwaiter().GetResult();`
125+
- `static Task Main()` results in the compiler emitting the equivalent of `private static void $GeneratedMain() => Main().GetAwaiter().GetResult();`.
126+
- `static Task Main(string[])` results in the compiler emitting the equivalent of `private static void $GeneratedMain(string[] args) => Main(args).GetAwaiter().GetResult();`.
127+
- `static Task<int> Main()` results in the compiler emitting the equivalent of `private static int $GeneratedMain() => Main().GetAwaiter().GetResult();`.
128+
- `static Task<int> Main(string[])` results in the compiler emitting the equivalent of `private static int $GeneratedMain(string[] args) => Main(args).GetAwaiter().GetResult();`.
129129

130130
> [!NOTE]
131-
>If the examples used `async` modifier on the `Main` method, the compiler would generate the same code.
131+
> If the examples use the `async` modifier on the `Main` method, the compiler generates the same code.
132132
133-
## Command-Line Arguments
133+
## Command-line arguments
134134

135135
You can send arguments to the `Main` method by defining the method in one of the following ways:
136136

@@ -141,7 +141,7 @@ You can send arguments to the `Main` method by defining the method in one of the
141141
| `static async Task Main(string[] args)` | Uses `await` but doesn't return a value |
142142
| `static async Task<int> Main(string[] args)` | Return a value and uses `await` |
143143

144-
If the arguments aren't used, you can omit `args` from the method declaration for slightly simpler code:
144+
If you don't use the arguments, you can omit `args` from the method declaration for slightly simpler code:
145145

146146
| `Main` declaration | `Main` method code |
147147
|---------------------------------|-----------------------------------------|
@@ -153,7 +153,7 @@ If the arguments aren't used, you can omit `args` from the method declaration fo
153153
> [!NOTE]
154154
> You can also use <xref:System.Environment.CommandLine%2A?displayProperty=nameWithType> or <xref:System.Environment.GetCommandLineArgs%2A?displayProperty=nameWithType> to access the command-line arguments from any point in a console or Windows Forms application. To enable command-line arguments in the `Main` method declaration in a Windows Forms application, you must manually modify the declaration of `Main`. The code generated by the Windows Forms designer creates `Main` without an input parameter.
155155
156-
The parameter of the `Main` method is a <xref:System.String> array that represents the command-line arguments. Usually you determine whether arguments exist by testing the `Length` property, for example:
156+
The parameter of the `Main` method is a <xref:System.String> array that represents the command-line arguments. Usually, you determine whether arguments exist by testing the `Length` property, for example:
157157

158158
:::code language="csharp" source="snippets/main-command-line/Program.cs" ID="Snippet4":::
159159

@@ -189,28 +189,28 @@ To compile and run the application from a command prompt, follow these steps:
189189

190190
1. Paste the following code into any text editor, and then save the file as a text file with the name *Factorial.cs*.
191191

192-
:::code language="csharp" source="./snippets/main-command-line/Factorial.cs":::
192+
:::code language="csharp" source="./snippets/main-command-line/Factorial.cs":::
193193

194-
At the beginning of the `Main` method the program tests if input arguments weren't supplied comparing length of `args` argument to `0` and displays the help if no arguments are found.<br/>
195-
If arguments are provided (`args.Length` is greater than 0), the program tries to convert the input arguments to numbers. This example throws an exception if the argument isn't a number.<br/>
196-
After factorial is calculated (stored in `result` variable of type `long`), the verbose result is printed depending on the `result` variable.
194+
At the beginning of the `Main` method, the program tests if input arguments weren't supplied by comparing the length of the `args` argument to `0` and displays the help if no arguments are found.<br/>
195+
If arguments are provided (`args.Length` is greater than 0), the program tries to convert the input arguments to numbers. This example throws an exception if the argument isn't a number.<br/>
196+
After factorial is calculated (stored in `result` variable of type `long`), the verbose result is printed depending on the `result` variable.
197197

198-
2. From the **Start** screen or **Start** menu, open a Visual Studio **Developer Command Prompt** window, and then navigate to the folder that contains the file that you created.
198+
1. From the **Start** screen or **Start** menu, open a Visual Studio **Developer Command Prompt** window, and then navigate to the folder that contains the file that you created.
199199

200-
3. To compile the application, enter the following command:
201-
202-
`dotnet build`
203-
204-
If your application has no compilation errors, a binary file named *Factorial.dll* is created.
205-
206-
4. Enter the following command to calculate the factorial of 3:
207-
208-
`dotnet run -- 3`
209-
210-
5. If 3 is entered on command line as the program's argument, the output reads: `The factorial of 3 is 6.`
200+
1. To compile the application, enter the following command:
201+
202+
`dotnet build`
203+
204+
If your application has no compilation errors, the build process creates a binary file named *Factorial.dll*.
205+
206+
1. Enter the following command to calculate the factorial of 3:
207+
208+
`dotnet run -- 3`
209+
210+
1. If you enter 3 on the command line as the program's argument, the output reads: `The factorial of 3 is 6.`
211211

212212
> [!NOTE]
213-
> When running an application in Visual Studio, you can specify command-line arguments in the [Debug Page, Project Designer](/visualstudio/ide/reference/debug-page-project-designer).
213+
> When running an application in Visual Studio, specify command-line arguments in the [Debug Page, Project Designer](/visualstudio/ide/reference/debug-page-project-designer).
214214
215215
## C# language specification
216216

docs/csharp/language-reference/keywords/access-modifiers.md

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,29 +1,29 @@
11
---
22
description: "Access Modifiers - C# Reference"
33
title: "Access Modifiers"
4-
ms.date: 09/15/2022
4+
ms.date: 12/15/2025
55
helpviewer_keywords:
66
- "access modifiers [C#]"
77
---
8-
# Access Modifiers (C# Reference)
8+
# Access modifiers (C# reference)
99

10-
Access modifiers are keywords used to specify the declared accessibility of a member or a type. This section introduces the five access modifiers:
10+
Use access modifiers to specify the declared accessibility of a member or a type. This section introduces the four access modifiers:
1111

1212
- `public`
1313
- `protected`
1414
- `internal`
1515
- `private`
16-
- `file`
1716

18-
The following seven accessibility levels can be specified using the access modifiers:
17+
By using these access modifiers, you can specify the following six accessibility levels:
1918

20-
- [`public`](public.md): Access isn't restricted.
19+
- [`public`](public.md): No access restrictions.
2120
- [`protected`](protected.md): Access is limited to the containing class or types derived from the containing class.
2221
- [`internal`](internal.md): Access is limited to the current assembly.
2322
- [`protected internal`](protected-internal.md): Access is limited to the current assembly or types derived from the containing class.
2423
- [`private`](private.md): Access is limited to the containing type.
2524
- [`private protected`](private-protected.md): Access is limited to the containing class or types derived from the containing class within the current assembly.
26-
- [`file`](file.md): The declared type is only visible in the current source file. File scoped types are generally used for source generators.
25+
26+
In addition, a top-level (non-nested) type can use the [`file`](file.md) modifier. The declared type is only visible in the current source file. File scoped types are generally used for source generators. You can't combine the `file` modifier with any access modifier.
2727

2828
This section also introduces the following concepts:
2929

0 commit comments

Comments
 (0)