diff --git a/docs/csharp/fundamentals/program-structure/main-command-line.md b/docs/csharp/fundamentals/program-structure/main-command-line.md index 9821df757dc56..cff65bf66216b 100644 --- a/docs/csharp/fundamentals/program-structure/main-command-line.md +++ b/docs/csharp/fundamentals/program-structure/main-command-line.md @@ -1,7 +1,7 @@ --- title: "Main() and command-line arguments" description: Learn about Main() and command-line arguments. The 'Main' method is the entry point of an executable program. -ms.date: 06/23/2025 +ms.date: 12/15/2025 f1_keywords: - "main_CSharpKeyword" - "Main" @@ -14,27 +14,27 @@ helpviewer_keywords: --- # Main() and command-line arguments -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. +The runtime calls the `Main` method when you start a C# application. The `Main` method is the entry point of a C# application. -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: +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: :::code language="csharp" source="snippets/main-command-line/TestClass.cs"::: -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`): +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`): :::code language="csharp" source="snippets/top-level-statements-1/Program.cs"::: -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 `, or using the `#!/usr/local/share/dotnet/dotnet run` directive as the first line (unix shells only). +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 `, or by using the `#!/usr/bin/env dotnet run` directive as the first line (Unix shells only). ## Overview -- The `Main` method is the entry point of an executable program; it's where the program control starts and ends. -- `Main` must be declared inside a class or struct. The enclosing `class` can be `static`. +- The `Main` method is the entry point of an executable program. It's where the program control starts and ends. +- You must declare `Main` inside a class or struct. The enclosing `class` can be `static`. - `Main` must be [`static`](../../language-reference/keywords/static.md). -- `Main` can have any [access modifier](../../programming-guide/classes-and-structs/access-modifiers.md) (except `file`). -- `Main` can either have a `void`, `int`, `Task`, or `Task` return type. +- `Main` can have any [access modifier](../../programming-guide/classes-and-structs/access-modifiers.md). +- `Main` can return `void`, `int`, `Task`, or `Task`. - If and only if `Main` returns a `Task` or `Task`, the declaration of `Main` can include the [`async`](../../language-reference/keywords/async.md) modifier. This rule specifically excludes an `async void Main` method. -- 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 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 method. +- 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 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 method. The following list shows the most common `Main` declarations: @@ -49,10 +49,10 @@ static async Task Main(string[] args) { } static async Task Main(string[] args) { } ``` -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. +The preceding examples don't specify an access modifier, so they're implicitly `private` by default. You can specify any explicit access modifier. > [!TIP] -> The addition of `async` and `Task`, `Task` return types simplifies program code when console applications need to start and `await` asynchronous operations in `Main`. +> By using `async` and `Task` or `Task` return types, you simplify program code when console applications need to start and `await` asynchronous operations in `Main`. ## Main() return values @@ -86,13 +86,13 @@ Create a new application by running `dotnet new console`. Modify the `Main` meth Remember to save this program as *MainReturnValTest.cs*. -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. +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. -You can build the application using the [dotnet CLI](../../../core/tools/dotnet.md) `dotnet build` command. +You can build the application by using the [dotnet CLI](../../../core/tools/dotnet.md) `dotnet build` command. 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. -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. +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. ```powershell dotnet run @@ -116,21 +116,21 @@ When you declare an `async` return value for `Main`, the compiler generates the :::code language="csharp" source="snippets/main-arguments/Program.cs" id="AsyncMain"::: -In both examples main body of the program is within the body of `AsyncConsoleWork()` method. +In both examples, the main body of the program is within the body of the `AsyncConsoleWork()` method. An advantage of declaring `Main` as `async` is that the compiler always generates the correct code. When the application entry point returns a `Task` or `Task`, 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: -- `static Task Main()` results in the compiler emitting the equivalent of `private static void $GeneratedMain() => Main().GetAwaiter().GetResult();` -- `static Task Main(string[])` results in the compiler emitting the equivalent of `private static void $GeneratedMain(string[] args) => Main(args).GetAwaiter().GetResult();` -- `static Task Main()` results in the compiler emitting the equivalent of `private static int $GeneratedMain() => Main().GetAwaiter().GetResult();` -- `static Task Main(string[])` results in the compiler emitting the equivalent of `private static int $GeneratedMain(string[] args) => Main(args).GetAwaiter().GetResult();` +- `static Task Main()` results in the compiler emitting the equivalent of `private static void $GeneratedMain() => Main().GetAwaiter().GetResult();`. +- `static Task Main(string[])` results in the compiler emitting the equivalent of `private static void $GeneratedMain(string[] args) => Main(args).GetAwaiter().GetResult();`. +- `static Task Main()` results in the compiler emitting the equivalent of `private static int $GeneratedMain() => Main().GetAwaiter().GetResult();`. +- `static Task Main(string[])` results in the compiler emitting the equivalent of `private static int $GeneratedMain(string[] args) => Main(args).GetAwaiter().GetResult();`. > [!NOTE] ->If the examples used `async` modifier on the `Main` method, the compiler would generate the same code. +> If the examples use the `async` modifier on the `Main` method, the compiler generates the same code. -## Command-Line Arguments +## Command-line arguments You can send arguments to the `Main` method by defining the method in one of the following ways: @@ -141,7 +141,7 @@ You can send arguments to the `Main` method by defining the method in one of the | `static async Task Main(string[] args)` | Uses `await` but doesn't return a value | | `static async Task Main(string[] args)` | Return a value and uses `await` | -If the arguments aren't used, you can omit `args` from the method declaration for slightly simpler code: +If you don't use the arguments, you can omit `args` from the method declaration for slightly simpler code: | `Main` declaration | `Main` method code | |---------------------------------|-----------------------------------------| @@ -153,7 +153,7 @@ If the arguments aren't used, you can omit `args` from the method declaration fo > [!NOTE] > You can also use or 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. -The parameter of the `Main` method is a array that represents the command-line arguments. Usually you determine whether arguments exist by testing the `Length` property, for example: +The parameter of the `Main` method is a array that represents the command-line arguments. Usually, you determine whether arguments exist by testing the `Length` property, for example: :::code language="csharp" source="snippets/main-command-line/Program.cs" ID="Snippet4"::: @@ -189,28 +189,28 @@ To compile and run the application from a command prompt, follow these steps: 1. Paste the following code into any text editor, and then save the file as a text file with the name *Factorial.cs*. - :::code language="csharp" source="./snippets/main-command-line/Factorial.cs"::: + :::code language="csharp" source="./snippets/main-command-line/Factorial.cs"::: - 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.
- 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.
- After factorial is calculated (stored in `result` variable of type `long`), the verbose result is printed depending on the `result` variable. + 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.
+ 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.
+ After factorial is calculated (stored in `result` variable of type `long`), the verbose result is printed depending on the `result` variable. -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. +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. -3. To compile the application, enter the following command: - - `dotnet build` - - If your application has no compilation errors, a binary file named *Factorial.dll* is created. - -4. Enter the following command to calculate the factorial of 3: - - `dotnet run -- 3` - -5. If 3 is entered on command line as the program's argument, the output reads: `The factorial of 3 is 6.` +1. To compile the application, enter the following command: + + `dotnet build` + + If your application has no compilation errors, the build process creates a binary file named *Factorial.dll*. + +1. Enter the following command to calculate the factorial of 3: + + `dotnet run -- 3` + +1. If you enter 3 on the command line as the program's argument, the output reads: `The factorial of 3 is 6.` > [!NOTE] -> 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). +> When running an application in Visual Studio, specify command-line arguments in the [Debug Page, Project Designer](/visualstudio/ide/reference/debug-page-project-designer). ## C# language specification diff --git a/docs/csharp/language-reference/keywords/access-modifiers.md b/docs/csharp/language-reference/keywords/access-modifiers.md index c6e89a4e41c03..3e55fd838d60b 100644 --- a/docs/csharp/language-reference/keywords/access-modifiers.md +++ b/docs/csharp/language-reference/keywords/access-modifiers.md @@ -1,29 +1,29 @@ --- description: "Access Modifiers - C# Reference" title: "Access Modifiers" -ms.date: 09/15/2022 +ms.date: 12/15/2025 helpviewer_keywords: - "access modifiers [C#]" --- -# Access Modifiers (C# Reference) +# Access modifiers (C# reference) -Access modifiers are keywords used to specify the declared accessibility of a member or a type. This section introduces the five access modifiers: +Use access modifiers to specify the declared accessibility of a member or a type. This section introduces the four access modifiers: - `public` - `protected` - `internal` - `private` -- `file` - The following seven accessibility levels can be specified using the access modifiers: +By using these access modifiers, you can specify the following six accessibility levels: -- [`public`](public.md): Access isn't restricted. +- [`public`](public.md): No access restrictions. - [`protected`](protected.md): Access is limited to the containing class or types derived from the containing class. - [`internal`](internal.md): Access is limited to the current assembly. - [`protected internal`](protected-internal.md): Access is limited to the current assembly or types derived from the containing class. - [`private`](private.md): Access is limited to the containing type. - [`private protected`](private-protected.md): Access is limited to the containing class or types derived from the containing class within the current assembly. -- [`file`](file.md): The declared type is only visible in the current source file. File scoped types are generally used for source generators. + +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. This section also introduces the following concepts: diff --git a/docs/csharp/language-reference/keywords/accessibility-levels.md b/docs/csharp/language-reference/keywords/accessibility-levels.md index 4b183cc537c59..759a998970f70 100644 --- a/docs/csharp/language-reference/keywords/accessibility-levels.md +++ b/docs/csharp/language-reference/keywords/accessibility-levels.md @@ -1,54 +1,55 @@ --- description: "Accessibility Levels - C# Reference" title: "Accessibility Levels" -ms.date: 12/06/2017 +ms.date: 12/15/2025 helpviewer_keywords: - "access modifiers [C#], accessibility levels" - "accessibility levels" -ms.assetid: dc083921-0073-413e-8936-a613e8bb7df4 --- -# Accessibility Levels (C# Reference) +# Accessibility levels (C# reference) -Use the access modifiers, `public`, `protected`, `internal`, or `private`, to specify one of the following declared accessibility levels for members. - -|Declared accessibility|Meaning| -|----------------------------|-------------| -|[`public`](public.md)|Access is not restricted.| -|[`protected`](protected.md)|Access is limited to the containing class or types derived from the containing class.| -|[`internal`](internal.md)|Access is limited to the current assembly.| -|[`protected internal`](protected-internal.md)|Access is limited to the current assembly or types derived from the containing class.| -|[`private`](private.md)|Access is limited to the containing type.| -|[`private protected`](private-protected.md)|Access is limited to the containing class or types derived from the containing class within the current assembly. | - - Only one access modifier is allowed for a member or type, except when you use the `protected internal` or `private protected` combinations. - - Access modifiers are not allowed on namespaces. Namespaces have no access restrictions. - - Depending on the context in which a member declaration occurs, only certain declared accessibilities are permitted. If no access modifier is specified in a member declaration, a default accessibility is used. - - Top-level types, which are not nested in other types, can only have `internal` or `public` accessibility. The default accessibility for these types is `internal`. - - Nested types, which are members of other types, can have declared accessibilities as indicated in the following table. +Use the access modifiers `public`, `protected`, `internal`, or `private` to specify one of the following declared accessibility levels for members. + +| Declared accessibility | Meaning | +|-----------------------------------------------|-------------------------------------------------------------| +| [`public`](public.md) | Access isn't restricted. | +| [`protected`](protected.md) | Access is limited to the containing class or types derived from the containing class. | +| [`internal`](internal.md) | Access is limited to the current assembly. | +| [`protected internal`](protected-internal.md) | Access is limited to the current assembly or types derived from the containing class. | +| [`private`](private.md) | Access is limited to the containing type. | +| [`private protected`](private-protected.md) | Access is limited to the containing class or types derived from the containing class within the current assembly. | + +Top-level (non-nested) types can use the [file](../../language-reference/keywords/file.md) modifier. The `file` modifier restricts access to code in the same source file. You can't combine the `file` modifier with any access modifier. + +Use only one access modifier for a member or type, except when you use the `protected internal` or `private protected` combinations. -|Members of|Default member accessibility|Allowed declared accessibility of the member| -|----------------|----------------------------------|--------------------------------------------------| -|`enum`|`public`|None| -|`class`|`private`|`public`

`protected`

`internal`

`private`

`protected internal`

`private protected`| -|`interface`|`public`|`public`

`protected`

`internal`

`private`\*

`protected internal`

`private protected`| -|`struct`|`private`|`public`

`internal`

`private`| +Don't use access modifiers on namespaces. Namespaces have no access restrictions. + +Depending on the context in which a member declaration occurs, only certain declared accessibilities are permitted. If you don't specify an access modifier in a member declaration, a default accessibility is used. + +Top-level types, which aren't nested in other types, can only have `internal` or `public` accessibility. The default accessibility for these types is `internal`. + +Nested types, which are members of other types, can have declared accessibilities as indicated in the following table. + +| Members of | Default member accessibility | Allowed declared accessibility of the member | +|-------------|------------------------------|--------------------------------------------------------------------------------------------------------------------------------------------------------| +| `enum` | `public` | None | +| `class` | `private` | `public`

`protected`

`internal`

`private`

`protected internal`

`private protected` | +| `interface` | `public` | `public`

`protected`

`internal`

`private`\*

`protected internal`

`private protected` | +| `struct` | `private` | `public`

`internal`

`private` | \* An `interface` member with `private` accessibility must have a default implementation. - -> [!NOTE] -> If a class or struct is modified with the [`record`](../builtin-types/record.md) keyword modifier, then the same access modifiers are allowed. -> Also, with the [`record`](../builtin-types/record.md) modifier the default member accessibility is still `private` both for class and the struct. - -The accessibility of a nested type depends on its [accessibility domain](./accessibility-domain.md), which is determined by both the declared accessibility of the member and the accessibility domain of the immediately containing type. However, the accessibility domain of a nested type cannot exceed that of the containing type. - -## C# Language Specification - [!INCLUDE[CSharplangspec](~/includes/csharplangspec-md.md)] - +> [!NOTE] +> If you modify a class or struct with the [`record`](../builtin-types/record.md) keyword modifier, use the same access modifiers. +> Also, with the [`record`](../builtin-types/record.md) modifier, the default member accessibility is still `private` for both class and struct. + +The accessibility of a nested type depends on its [accessibility domain](./accessibility-domain.md), which the declared accessibility of the member and the accessibility domain of the immediately containing type determine. However, the accessibility domain of a nested type can't exceed that of the containing type. + +## C# Language Specification + +[!INCLUDE[CSharplangspec](~/includes/csharplangspec-md.md)] + ## See also - [C# Keywords](./index.md) diff --git a/docs/csharp/programming-guide/classes-and-structs/access-modifiers.md b/docs/csharp/programming-guide/classes-and-structs/access-modifiers.md index 48dd93f80cc48..1df81202c0cc0 100644 --- a/docs/csharp/programming-guide/classes-and-structs/access-modifiers.md +++ b/docs/csharp/programming-guide/classes-and-structs/access-modifiers.md @@ -1,14 +1,14 @@ --- title: "Access Modifiers" description: All types and type members in C# have an accessibility level that controls whether they can be used from other code. Review this list of access modifiers. -ms.date: 10/10/2025 +ms.date: 12/15/2025 helpviewer_keywords: - "C# Language, access modifiers" - "access modifiers [C#], about" --- -# Access Modifiers (C# Programming Guide) +# Access modifiers (C# programming guide) -All types and type members have an accessibility level. The accessibility level controls whether they can be used from other code in your assembly or other assemblies. An [assembly](../../../standard/glossary.md#assembly) is a *.dll* or *.exe* created by compiling one or more *.cs* files in a single compilation. Use the following access modifiers to specify the accessibility of a type or member when you declare it: +All types and type members have an accessibility level. The accessibility level controls whether other code in your assembly or other assemblies can use them. An [assembly](../../../standard/glossary.md#assembly) is a *.dll* or *.exe* created by compiling one or more *.cs* files in a single compilation. Use the following access modifiers to specify the accessibility of a type or member when you declare it: - [public](../../language-reference/keywords/public.md): Code in any assembly can access this type or member. The accessibility level of the containing type controls the accessibility level of public members of the type. - [private](../../language-reference/keywords/private.md): Only code declared in the same `class` or `struct` can access this member. @@ -16,7 +16,8 @@ All types and type members have an accessibility level. The accessibility level - [internal](../../language-reference/keywords/internal.md): Only code in the same assembly can access this type or member. - [protected internal](../../language-reference/keywords/protected-internal.md): Only code in the same assembly *or* in a derived class in another assembly can access this type or member. - [private protected](../../language-reference/keywords/private-protected.md): Only code in the same assembly *and* in the same class or a derived class can access the type or member. -- [file](../../language-reference/keywords/file.md): Only code in the same file can access the type or member. + +Use the [file](../../language-reference/keywords/file.md) modifier for top-level (non-nested) types. The `file` modifier restricts access to code in the same source file. You can't combine the `file` modifier with any access modifier. The [`record`](../../language-reference/builtin-types/record.md) modifier on a type causes the compiler to synthesize extra members. The `record` modifier doesn't affect the default accessibility for either a `record class` or a `record struct`. @@ -32,17 +33,17 @@ The [`record`](../../language-reference/builtin-types/record.md) modifier on a t The following examples demonstrate how to specify access modifiers on a type and member: -[!code-csharp[PublicAccess](~/samples/snippets/csharp/objectoriented/accessmodifiers.cs#PublicAccess)] +:::code language="csharp" source="./snippets/access-modifiers/accessmodifiers.cs" id="PublicAccess"::: Not all access modifiers are valid for all types or members in all contexts. In some cases, the accessibility of the containing type constrains the accessibility of its members. -Multiple declarations of a [partial class or partial member](./partial-classes-and-methods.md) must have the same accessibility. If one declaration of the partial class or member doesn't include an access modifier, the other declarations can't declare an access modifier. The compiler generates an error if multiple declarations for the partial class or method declare different accessibilities. +Multiple declarations of a [partial class or partial member](./partial-classes-and-methods.md) must have the same accessibility. If one declaration doesn't include an access modifier, the other declarations can't declare an access modifier. The compiler generates an error if multiple declarations for the partial class or method declare different accessibilities. ## Class and struct accessibility -Classes and structs declared directly within a namespace (aren't nested within other classes or structs) can have `public`, `internal`, or `file` access. `internal` is the default if no access modifier is specified. +Classes and structs declared directly within a namespace (aren't nested within other classes or structs) can have `public` or `internal` access. If you don't specify an access modifier, the default is `internal`. You can also use the `file` modifier to restrict access to the current source file. -Struct members, including nested classes and structs, can be declared `public`, `internal`, or `private`. Class members, including nested classes and structs, can be `public`, `protected internal`, `protected`, `internal`, `private protected`, or `private`. Class and struct members, including nested classes and structs, have `private` access by default. +You can declare struct members, including nested classes and structs, as `public`, `internal`, or `private`. You can declare class members, including nested classes and structs, as `public`, `protected internal`, `protected`, `internal`, `private protected`, or `private`. By default, class and struct members, including nested classes and structs, have `private` access. Derived classes can't have greater accessibility than their base types. You can't declare a public class `B` that derives from an internal class `A`. If allowed, it would have the effect of making `A` public, because all `protected` or `internal` members of `A` are accessible from the derived class. @@ -50,7 +51,7 @@ You can enable specific other assemblies to access your internal types by using ## Other types -Interfaces declared directly within a namespace can be `public` or `internal` and, just like classes and structs, interfaces default to `internal` access. Interface members are `public` by default because the purpose of an interface is to enable other types to access a class or struct. Interface member declarations might include any access modifier. You use access modifiers on `interface` members to provide a common implementation needed by all implementors of an interface. +You can declare interfaces directly within a namespace as `public` or `internal`. Just like classes and structs, interfaces default to `internal` access. Interface members are `public` by default because the purpose of an interface is to enable other types to access a class or struct. Interface member declarations might include any access modifier. Use access modifiers on `interface` members to provide a common implementation needed by all implementors of an interface. A [`delegate`](../delegates/index.md) type declared directly in a namespace has `internal` access by default. @@ -58,21 +59,19 @@ For more information about access modifiers, see the [Accessibility Levels](../. ## Member accessibility -Members of a `class` or `struct` (including nested classes and structs) can be declared with any of the six types of access. Struct members can't be declared as `protected`, `protected internal`, or `private protected` because structs don't support inheritance. +You can declare members of a `class` or `struct` (including nested classes and structs) with any of the six types of access. You can't declare struct members as `protected`, `protected internal`, or `private protected` because structs don't support inheritance. -Normally, the accessibility of a member isn't greater than the accessibility of the type that contains it. However, a `public` member of an `internal` class might be accessible from outside the assembly if the member implements interface methods or overrides virtual methods that are defined in a public base class. +Normally, the accessibility of a member isn't greater than the accessibility of the type that contains it. However, you can access a `public` member of an `internal` class from outside the assembly if the member implements interface methods or overrides virtual methods that are defined in a public base class. The type of any member field, property, or event must be at least as accessible as the member itself. Similarly, the return type and the parameter types of any method, indexer, or delegate must be at least as accessible as the member itself. For example, you can't have a `public` method `M` that returns a class `C` unless `C` is also `public`. Likewise, you can't have a `protected` property of type `A` if `A` is declared as `private`. -User-defined operators must always be declared as `public`. For more information, see [Operator overloading](../../language-reference/operators/operator-overloading.md). +You must always declare user-defined operators as `public`. For more information, see [Operator overloading](../../language-reference/operators/operator-overloading.md). To set the access level for a `class` or `struct` member, add the appropriate keyword to the member declaration, as shown in the following example. -[!code-csharp[MethodAccess](~/samples/snippets/csharp/objectoriented/accessmodifiers.cs#MethodAccess)] - -Finalizers can't have accessibility modifiers. Members of an `enum` type are always `public`, and no access modifiers can be applied. +:::code language="csharp" source="./snippets/access-modifiers/accessmodifiers.cs" id="MethodAccess"::: -The `file` access modifier is allowed only on top-level (non-nested) type declarations. +Finalizers can't have accessibility modifiers. Members of an `enum` type are always `public`, and you can't apply access modifiers. ## C# language specification diff --git a/docs/csharp/programming-guide/classes-and-structs/nested-types.md b/docs/csharp/programming-guide/classes-and-structs/nested-types.md index d1cf12ac1d417..8770f1f6a6bd3 100644 --- a/docs/csharp/programming-guide/classes-and-structs/nested-types.md +++ b/docs/csharp/programming-guide/classes-and-structs/nested-types.md @@ -1,24 +1,23 @@ --- title: "Nested Types" description: A type defined within a class, struct, or interface is called a nested type in C#. -ms.date: 02/08/2020 +ms.date: 12/15/2025 helpviewer_keywords: - "nested types [C#]" -ms.assetid: f2e1b315-e3d1-48ce-977f-7bae0960ba99 --- -# Nested Types (C# Programming Guide) +# Nested types (C# programming guide) -A type defined within a [class](../../language-reference/keywords/class.md), [struct](../../language-reference/builtin-types/struct.md), or [interface](../../language-reference/keywords/interface.md) is called a nested type. For example +A nested type is a type that you define within a [class](../../language-reference/keywords/class.md), [struct](../../language-reference/builtin-types/struct.md), or [interface](../../language-reference/keywords/interface.md). For example: -[!code-csharp[DeclareNestedClass](~/samples/snippets/csharp/objectoriented/nestedtypes.cs#DeclareNestedClass)] +:::code language="csharp" source="./snippets/access-modifiers/nestedtypes.cs" id="DeclareNestedClass"::: -Regardless of whether the outer type is a class, interface, or struct, nested types default to [private](../../language-reference/keywords/private.md); they are accessible only from their containing type. In the previous example, the `Nested` class is inaccessible to external types. +Regardless of whether the outer type is a class, interface, or struct, nested types default to [private](../../language-reference/keywords/private.md). You can access them only from their containing type. In the preceding example, external types can't access the `Nested` class. You can also specify an [access modifier](../../language-reference/keywords/access-modifiers.md) to define the accessibility of a nested type, as follows: -- Nested types of a **class** can be [public](../../language-reference/keywords/public.md), [protected](../../language-reference/keywords/protected.md), [internal](../../language-reference/keywords/internal.md), [protected internal](../../language-reference/keywords/protected-internal.md), [private](../../language-reference/keywords/private.md) or [private protected](../../language-reference/keywords/private-protected.md). +- Nested types of a **class** can be [public](../../language-reference/keywords/public.md), [protected](../../language-reference/keywords/protected.md), [internal](../../language-reference/keywords/internal.md), [protected internal](../../language-reference/keywords/protected-internal.md), [private](../../language-reference/keywords/private.md), or [private protected](../../language-reference/keywords/private-protected.md). - However, defining a `protected`, `protected internal` or `private protected` nested class inside a [sealed class](../../language-reference/keywords/sealed.md) generates compiler warning [CS0628](../../misc/cs0628.md), "new protected member declared in sealed class." + However, defining a `protected`, `protected internal`, or `private protected` nested class inside a [sealed class](../../language-reference/keywords/sealed.md) generates compiler warning [CS0628](../../misc/cs0628.md), "new protected member declared in sealed class." Also be aware that making a nested type externally visible violates the code quality rule [CA1034](../../../fundamentals/code-analysis/quality-rules/ca1034.md) "Nested types should not be visible". @@ -26,17 +25,17 @@ You can also specify an [access modifier](../../language-reference/keywords/acce The following example makes the `Nested` class public: -[!code-csharp[PublicNestedClass](~/samples/snippets/csharp/objectoriented/nestedtypes.cs#PublicNestedClass)] +:::code language="csharp" source="./snippets/access-modifiers/nestedtypes.cs" id="PublicNestedClass"::: The nested, or inner, type can access the containing, or outer, type. To access the containing type, pass it as an argument to the constructor of the nested type. For example: -[!code-csharp[DeclareNestedInstance](~/samples/snippets/csharp/objectoriented/nestedtypes.cs#DeclareNestedInstance)] +:::code language="csharp" source="./snippets/access-modifiers/nestedtypes.cs" id="DeclareNestedInstance"::: A nested type has access to all of the members that are accessible to its containing type. It can access private and protected members of the containing type, including any inherited protected members. In the previous declaration, the full name of class `Nested` is `Container.Nested`. This is the name used to create a new instance of the nested class, as follows: -[!code-csharp[UseNestedInstance](~/samples/snippets/csharp/objectoriented/nestedtypes.cs#UseNestedInstance)] +:::code language="csharp" source="./snippets/access-modifiers/nestedtypes.cs" id="UseNestedInstance"::: ## See also diff --git a/docs/csharp/programming-guide/classes-and-structs/snippets/access-modifiers/Program.cs b/docs/csharp/programming-guide/classes-and-structs/snippets/access-modifiers/Program.cs new file mode 100644 index 0000000000000..021fba5e1bb52 --- /dev/null +++ b/docs/csharp/programming-guide/classes-and-structs/snippets/access-modifiers/Program.cs @@ -0,0 +1 @@ +objectoriented.NestedTypes.Example(); diff --git a/docs/csharp/programming-guide/classes-and-structs/snippets/access-modifiers/accessmodifiers.cs b/docs/csharp/programming-guide/classes-and-structs/snippets/access-modifiers/accessmodifiers.cs new file mode 100644 index 0000000000000..e9a11a9dab8b2 --- /dev/null +++ b/docs/csharp/programming-guide/classes-and-structs/snippets/access-modifiers/accessmodifiers.cs @@ -0,0 +1,23 @@ +namespace objectoriented; + +// +public class Bicycle +{ + public void Pedal() { } +} +// + +// +// public class: +public class Tricycle +{ + // protected method: + protected void Pedal() { } + + // private field: + private int _wheels = 3; + + // protected internal property: + protected internal int Wheels => _wheels; +} +// diff --git a/samples/snippets/csharp/objectoriented/nestedtypes.cs b/docs/csharp/programming-guide/classes-and-structs/snippets/access-modifiers/nestedtypes.cs similarity index 100% rename from samples/snippets/csharp/objectoriented/nestedtypes.cs rename to docs/csharp/programming-guide/classes-and-structs/snippets/access-modifiers/nestedtypes.cs diff --git a/samples/snippets/csharp/objectoriented/objectoriented.csproj b/docs/csharp/programming-guide/classes-and-structs/snippets/access-modifiers/objectoriented.csproj similarity index 76% rename from samples/snippets/csharp/objectoriented/objectoriented.csproj rename to docs/csharp/programming-guide/classes-and-structs/snippets/access-modifiers/objectoriented.csproj index af31fefa23aa5..f9929d13fb73d 100644 --- a/samples/snippets/csharp/objectoriented/objectoriented.csproj +++ b/docs/csharp/programming-guide/classes-and-structs/snippets/access-modifiers/objectoriented.csproj @@ -2,7 +2,7 @@ Exe - net8.0 + net10.0 enable diff --git a/samples/snippets/csharp/objectoriented/Program.cs b/samples/snippets/csharp/objectoriented/Program.cs deleted file mode 100644 index 0fdd9aa7fc7a2..0000000000000 --- a/samples/snippets/csharp/objectoriented/Program.cs +++ /dev/null @@ -1,12 +0,0 @@ -using System; - -namespace objectoriented -{ - class Program - { - static void Main(string[] args) - { - NestedTypes.Example(); - } - } -} diff --git a/samples/snippets/csharp/objectoriented/accessmodifiers.cs b/samples/snippets/csharp/objectoriented/accessmodifiers.cs deleted file mode 100644 index 76d8cd76478cc..0000000000000 --- a/samples/snippets/csharp/objectoriented/accessmodifiers.cs +++ /dev/null @@ -1,24 +0,0 @@ -namespace objectoriented -{ - // - public class Bicycle - { - public void Pedal() { } - } - // - - // - // public class: - public class Tricycle - { - // protected method: - protected void Pedal() { } - - // private field: - private int _wheels = 3; - - // protected internal property: - protected internal int Wheels => _wheels; - } - // -} \ No newline at end of file