Skip to content

C# 11: required members #30275

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

Merged
merged 16 commits into from
Jul 29, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
10 changes: 7 additions & 3 deletions docs/csharp/language-reference/attributes/general.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
---
title: "Attributes interpreted by the C# compiler: Miscellaneous"
ms.date: 12/21/2021
ms.date: 07/20/2022
description: "Learn about attributes that affect code generated by the compiler: the Conditional, Obsolete, AttributeUsage, ModuleInitializer, and SkipLocalsInit attributes."
---
# Miscellaneous attributes interpreted by the C# compiler
Expand Down Expand Up @@ -47,6 +47,10 @@ In C# 10, you can use constant string interpolation and the `nameof` operator to

:::code language="csharp" source="snippets/ObsoleteExample.cs" id="Snippet2" :::

## `SetsRequiredMembers` attribute

The `SetsRequiredMembers` attribute informs the compiler that a constructor sets all `required` members in that class or struct. The compiler assumes any constructor with the <xref:System.Diagnostics.CodeAnalysis.SetsRequiredMembersAttribute?displayProperty=fullName> attribute initializes all `required` members. Any code that invokes such a constructor doesn't need object initializers to set required members.

## `AttributeUsage` attribute

The `AttributeUsage` attribute determines how a custom attribute class can be used. <xref:System.AttributeUsageAttribute> is an attribute you apply to custom attribute definitions. The `AttributeUsage` attribute enables you to control:
Expand Down Expand Up @@ -149,7 +153,7 @@ You can learn more about building an interpolated string handler in the C# 10 fe

## `ModuleInitializer` attribute

Starting with C# 9, the `ModuleInitializer` attribute marks a method that the runtime calls when the assembly loads. `ModuleInitializer` is an alias for <xref:System.Runtime.CompilerServices.ModuleInitializerAttribute>.
Beginning with C# 9, the `ModuleInitializer` attribute marks a method that the runtime calls when the assembly loads. `ModuleInitializer` is an alias for <xref:System.Runtime.CompilerServices.ModuleInitializerAttribute>.

The `ModuleInitializer` attribute can only be applied to a method that:

Expand All @@ -173,7 +177,7 @@ Source code generators sometimes need to generate initialization code. Module in

## `SkipLocalsInit` attribute

Starting in C# 9, the `SkipLocalsInit` attribute prevents the compiler from setting the `.locals init` flag when emitting to metadata. The `SkipLocalsInit` attribute is a single-use attribute and can be applied to a method, a property, a class, a struct, an interface, or a module, but not to an assembly. `SkipLocalsInit` is an alias for <xref:System.Runtime.CompilerServices.SkipLocalsInitAttribute>.
Beginning in C# 9, the `SkipLocalsInit` attribute prevents the compiler from setting the `.locals init` flag when emitting to metadata. The `SkipLocalsInit` attribute is a single-use attribute and can be applied to a method, a property, a class, a struct, an interface, or a module, but not to an assembly. `SkipLocalsInit` is an alias for <xref:System.Runtime.CompilerServices.SkipLocalsInitAttribute>.

The `.locals init` flag causes the CLR to initialize all of the local variables declared in a method to their default values. Since the compiler also makes sure that you never use a variable before assigning some value to it, `.locals init` is typically not necessary. However, the extra zero-initialization may have measurable performance impact in some scenarios, such as when you use [stackalloc](../operators/stackalloc.md) to allocate an array on the stack. In those cases, you can add the `SkipLocalsInit` attribute. If applied to a method directly, the attribute affects that method and all its nested functions, including lambdas and local functions. If applied to a type or module, it affects all methods nested inside. This attribute doesn't affect abstract methods, but it does affect code generated for the implementation.

Expand Down
1 change: 1 addition & 0 deletions docs/csharp/language-reference/keywords/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -147,6 +147,7 @@ A contextual keyword is used to provide a specific meaning in the code, but it i
[`partial` (method)](partial-method.md)
[`record`](../../fundamentals/types/records.md)
[`remove`](remove.md)
[`required`](required.md)
[`select`](select-clause.md)
:::column-end:::
:::column:::
Expand Down
26 changes: 26 additions & 0 deletions docs/csharp/language-reference/keywords/required.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
---
description: "required modifier - C# Reference"
title: "required modifier - C# Reference"
ms.date: 07/20/2022
helpviewer_keywords:
- "required keyword [C#]"
---
# required modifier (C# Reference)

The `required` modifier indicates that the *field* or *property* it's applied to must be initialized by all constructors or using an [object initiializer](../../programming-guide/classes-and-structs/object-and-collection-initializers.md). Any expression that initializes a new instance of the type must initialize all *required members*. Constructors indicate that they initialize all required members by adding the [`SetsRequiredMembers`](../attributes/general.md#setsrequiredmembers-attribute) attribute in the constructor declaration. Code that uses a constructor without this attribute must use *object initializers* to initialize all `required` members. The `required` modifier is available beginning with C# 11.

The `required` modifier and the `SetsRequiredMembers` attribute enable developers to create types where properties or fields must be properly initialized, yet still allow initialization using either constructors or object initializers. Several rules ensure this behavior:

- The `required` modifier can be applied to *fields* and *properties* declared in `struct`, and `class` types, including `record` and `record struct` types. The `required` modifier can't be applied to members of an `interface`.
- Explicit interface implementations can't be marked as `required`. They can't be set in object initializers.
- Required members must be initialized, but they may be initialized to `null`. If the type is a non-nullable reference type, the compiler issues a warning if you initialize the member to `null`. The compiler issues an error if the member isn't initialized at all.
- Required members must be at least as visible as their containing type. For example, a `public` class can't contain a `required` field that's `protected`. Furthermore, required properties must have setters (`set` or `init` accessors) that are at least as visible as their containing types. Members that aren't accessible can't be set by code that creates an instance.
- Derived classes can't hide a `required` member declared in the base class. Hiding a required member prevents callers from using object initializers for it. Furthermore, derived types that override a required property must include the `required` modifier. The derived type can't remove the `required` state. Derived types can add the `required` modifier when overriding a property.
- A type with any `required` members may not be used as a type argument when the type parameter includes the `new()` constraint. The compiler can't enforce that all required members are initialized in the generic code.
- A constructor that chains to another constructor annotated with the `SetsRequiredMembers` attribute, either `this()`, or `base()`, must also include the `SetsRequiredMembers` attribute. That ensures that callers can correctly use all appropriate constructors.
- Copy constructors generated for `record` types have the `SetsRequiredMembers` attribute applied if any of the members are `required`.
- The `required` modifier isn't allowed on the declaration for positional parameters on a record.

The following code shows a class hierarchy that uses the `required` modifier for the `FirstName` and `LastName` properties:

:::code language="csharp" source="./snippets/RequiredExample.cs" id="SnippetRequired":::
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
using System.Diagnostics.CodeAnalysis;

namespace RequiredMembers;

// <SnippetRequired>
public class Person
{
public Person() { }

[SetsRequiredMembers]
public Person(string firstName, string lastName) =>
(FirstName, LastName) = (firstName, lastName);

public required string FirstName { get; init; }
public required string LastName { get; init; }

public int? Age { get; set; }
}

public class Student : Person
{
public Student() : base()
{
}

[SetsRequiredMembers]
public Student(string firstName, string lastName) :
base(firstName, lastName)
{
}

public double GPA { get; set; }
}
// </SnippetRequired>
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,11 @@

<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>net6.0</TargetFramework>
<TargetFramework>net7.0</TargetFramework>
<Nullable>enable</Nullable>
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
<StartupObject>keywords.Program</StartupObject>
<LangVersion>preview</LangVersion>
</PropertyGroup>

<ItemGroup>
Expand Down
Original file line number Diff line number Diff line change
@@ -1,23 +1,22 @@
---
title: "Auto-Implemented Properties - C# Programming Guide"
description: For an auto-implemented property in C#, the compiler creates a private, anonymous backing field accessed only through get and set accessors of the property.
ms.date: 01/31/2020
ms.date: 07/29/2022
f1_keywords:
- "propertyInitializer_CSharpKeyword"
helpviewer_keywords:
- "auto-implemented properties [C#]"
- "properties [C#], auto-implemented"
ms.assetid: aa55fa97-ccec-431f-b5e9-5ac789fd32b7
---
# Auto-Implemented Properties (C# Programming Guide)

In C# 3.0 and later, auto-implemented properties make property-declaration more concise when no additional logic is required in the property accessors. They also enable client code to create objects. When you declare a property as shown in the following example, the compiler creates a private, anonymous backing field that can only be accessed through the property's `get` and `set` accessors. In C# 9 and later, `init` accessors can also be declared as auto-implemented properties.
Auto-implemented properties make property-declaration more concise when no additional logic is required in the property accessors. They also enable client code to create objects. When you declare a property as shown in the following example, the compiler creates a private, anonymous backing field that can only be accessed through the property's `get` and `set` accessors. In C# 9 and later, `init` accessors can also be declared as auto-implemented properties.

## Example

The following example shows a simple class that has some auto-implemented properties:

[!code-csharp[csProgGuideLINQ#28](~/samples/snippets/csharp/VS_Snippets_VBCSharp/csProgGuideLINQ/CS/csRef30LangFeatures_2.cs#28)]
:::code language="csharp" source="./snippets/properties/AutoImplemented.cs" id="Snippet28":::

You can't declare auto-implemented properties in interfaces. Auto-implemented properties declare a private instance backing field, and interfaces may not declare instance fields. Declaring a property in an interface without defining a body declares a property with accessors that must be implemented by each type that implements that interface.

Expand Down
21 changes: 12 additions & 9 deletions docs/csharp/programming-guide/classes-and-structs/fields.md
Original file line number Diff line number Diff line change
@@ -1,32 +1,31 @@
---
title: Fields - C# Programming Guide
description: A field in C# is a variable of any type that is declared directly in a class or struct. Fields are members of their containing type.
ms.date: 07/20/2015
ms.date: 07/20/2022
helpviewer_keywords:
- "fields [C#]"
ms.assetid: 3cbb2f61-75f8-4cce-b4ef-f5d1b3de0db7
---
# Fields (C# Programming Guide)

A *field* is a variable of any type that is declared directly in a [class](../../language-reference/keywords/class.md) or [struct](../../language-reference/builtin-types/struct.md). Fields are *members* of their containing type.

A class or struct may have instance fields, static fields, or both. Instance fields are specific to an instance of a type. If you have a class T, with an instance field F, you can create two objects of type T, and modify the value of F in each object without affecting the value in the other object. By contrast, a static field belongs to the type itself, and is shared among all instances of that type. You can access the static field only by using the type name. If you access the static field by an instance name, you get [CS0176](../../misc/cs0176.md) compile-time error.
A class or struct may have instance fields, static fields, or both. Instance fields are specific to an instance of a type. If you have a class `T`, with an instance field `F`, you can create two objects of type `T`, and modify the value of `F` in each object without affecting the value in the other object. By contrast, a static field belongs to the type itself, and is shared among all instances of that type. You can access the static field only by using the type name. If you access the static field by an instance name, you get [CS0176](../../misc/cs0176.md) compile-time error.

Generally, you should use fields only for variables that have private or protected accessibility. Data that your type exposes to client code should be provided through [methods](./methods.md), [properties](./properties.md), and [indexers](../indexers/index.md). By using these constructs for indirect access to internal fields, you can guard against invalid input values. A private field that stores the data exposed by a public property is called a *backing store* or *backing field*.

Fields typically store the data that must be accessible to more than one type method and must be stored for longer than the lifetime of any single method. For example, a type that represents a calendar date might have three integer fields: one for the month, one for the day, and one for the year. Variables that are not used outside the scope of a single method should be declared as *local variables* within the method body itself.
Fields typically store the data that must be accessible to more than one type method and must be stored for longer than the lifetime of any single method. For example, a type that represents a calendar date might have three integer fields: one for the month, one for the day, and one for the year. Variables that aren't used outside the scope of a single method should be declared as *local variables* within the method body itself.

Fields are declared in the class or struct block by specifying the access level of the field, followed by the type of the field, followed by the name of the field. For example:

[!code-csharp[fields#1](snippets/fields/Program.cs#1)]
:::code language="csharp" source="./snippets/fields/Program.cs" id="Snippet1":::

To access a field in an instance, add a period after the instance name, followed by the name of the field, as in `instancename._fieldName`. For example:

[!code-csharp[fields#2](snippets/fields/Program.cs#2)]
:::code language="csharp" source="./snippets/fields/Program.cs" id="Snippet2":::

A field can be given an initial value by using the assignment operator when the field is declared. To automatically assign the `Day` field to `"Monday"`, for example, you would declare `Day` as in the following example:

[!code-csharp[fields#3](snippets/fields/Program.cs#3)]
:::code language="csharp" source="./snippets/fields/Program.cs" id="Snippet3":::

Fields are initialized immediately before the constructor for the object instance is called. If the constructor assigns the value of a field, it will overwrite any value given during field declaration. For more information, see [Using Constructors](./using-constructors.md).

Expand All @@ -35,9 +34,13 @@ Fields are initialized immediately before the constructor for the object instanc

Fields can be marked as [public](../../language-reference/keywords/public.md), [private](../../language-reference/keywords/private.md), [protected](../../language-reference/keywords/protected.md), [internal](../../language-reference/keywords/internal.md), [protected internal](../../language-reference/keywords/protected-internal.md), or [private protected](../../language-reference/keywords/private-protected.md). These access modifiers define how users of the type can access the fields. For more information, see [Access Modifiers](./access-modifiers.md).

A field can optionally be declared [static](../../language-reference/keywords/static.md). This makes the field available to callers at any time, even if no instance of the type exists. For more information, see [Static Classes and Static Class Members](./static-classes-and-static-class-members.md).
A field can optionally be declared [static](../../language-reference/keywords/static.md). Static fields are available to callers at any time, even if no instance of the type exists. For more information, see [Static Classes and Static Class Members](./static-classes-and-static-class-members.md).

A field can be declared [readonly](../../language-reference/keywords/readonly.md). A read-only field can only be assigned a value during initialization or in a constructor. A `static readonly` field is very similar to a constant, except that the C# compiler does not have access to the value of a static read-only field at compile time, only at run time. For more information, see [Constants](./constants.md).
A field can be declared [readonly](../../language-reference/keywords/readonly.md). A read-only field can only be assigned a value during initialization or in a constructor. A `static readonly` field is similar to a constant, except that the C# compiler doesn't have access to the value of a static read-only field at compile time, only at run time. For more information, see [Constants](./constants.md).

A field can be declared [required](../../language-reference/keywords/required.md). A required field must be initialized by the constructor, or by an [object initializers](../../programming-guide/classes-and-structs/object-and-collection-initializers.md) when an object is created. You add the <xref:System.Diagnostics.CodeAnalysis.SetsRequiredMembersAttribute?displayProperty=fullName> attribute to any constructor declaration that initializes all required members.

The `required` modifier can't be combined with the `readonly` modifier on the same field.

## C# language specification

Expand Down
Loading