Skip to content
60 changes: 60 additions & 0 deletions standard/attributes.md
Original file line number Diff line number Diff line change
Expand Up @@ -498,6 +498,7 @@ A number of attributes affect the language in some way. These attributes include
- `System.Runtime.CompilerServices.EnumeratorCancellationAttribute` ([§23.5.8](attributes.md#2358-the-enumeratorcancellation-attribute)), which is used to specify parameter for the cancellation token in an asynchronous iterator.
- `System.Runtime.CompilerServices.ModuleInitializer` ([§23.5.9](attributes.md#2359-the-moduleinitializer-attribute)), which is used to mark a method as a module initializer.
- `System.Runtime.CompilerServices.InterpolatedStringHandlerAttribute` and `System.Runtime.CompilerServices.InterpolatedStringHandlerArgumentAttribute`, which are used to declare a custom interpolated string expression handler ([§23.5.9.1](attributes.md#23591-custom-interpolated-string-expression-handlers)) and to call one of its constructors, respectively.
- `System.Diagnostics.CodeAnalysis.SetsRequiredMembersAttribute` (§SetsRequiredMembers) and `System.Runtime.CompilerServices.RequiredMemberAttribute` (§RequiredMember), which are used in required-member contexts ([§15.7.1](classes.md#1571-general)).

The Nullable static analysis attributes ([§23.5.7](attributes.md#2357-code-analysis-attributes)) can improve the correctness of warnings generated for nullabilities and null states ([§8.9.5](types.md#895-nullabilities-and-null-states)).

Expand Down Expand Up @@ -1428,6 +1429,65 @@ Attribute `InterpolatedStringHandlerArgument` is applied to the handler paramete

If an `out bool` parameter is also declared to allow the handler to be inhibited ([§23.5.9.1.2](attributes.md#235912-inhibiting-a-custom-handler)) that parameter shall be the final one.

### §Required-Member-Attributes Required member attributes

#### §SetsRequiredMembers The SetsRequiredMembers attribute

This attribute indicates that the constructor it decorates sets all required members for the current type, so callers do not need to set any required members themselves. However, the compiler doesn't verify that the constructor actually initializes all required members.

> *Example*:
>
> <!-- Example: {template:"standalone-lib", name:"SetsRequiredMembers", expectedErrors:["CS9035","CS9035"]} -->
> ```csharp
> 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; }
> }
>
> public class Test
> {
> public static void M()
> {
> var p1 = new Student(); // error: doesn't set required members
> var p2 = new Student("Jane", "Williams"); // OK
> }
> }
> ```
>
> *end example*
<!-- markdownlint-disable MD028 -->

<!-- markdownlint-enable MD028 -->
> *Note*: As the derived-type constructor `Student(string, string)` chains to the base-type constructor `Person(string, string)`, which has this attribute, the derived-type constructor must also have that attribute ([§15.11.1](classes.md#15111-general)). *end note*

#### §RequiredMember The RequiredMember attribute

This attribute indicates that the current type has one or more required members ([§15.7.1](classes.md#1571-general)), or that a specific member of that type is required. However, it is an error for this attribute to be used explicitly. Instead, the presence of the modifier `required` results in the type or member being treated as if it were decorated with this attribute.

## 23.6 Attributes for interoperation

For interoperation with other languages, an indexer may be implemented using indexed properties. If no `IndexerName` attribute is present for an indexer, then the name `Item` is used by default. The `IndexerName` attribute enables a developer to override this default and specify a different name.
Expand Down
44 changes: 42 additions & 2 deletions standard/classes.md
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,8 @@ class_tag

A *class_declaration* consists of an optional set of *attributes* ([§23](attributes.md#23-attributes)), followed by an optional set of *class_modifier*s ([§15.2.2](classes.md#1522-class-modifiers)), followed by an optional `partial` modifier ([§15.2.7](classes.md#1527-partial-type-declarations)), followed by a *class_tag* and an *identifier* that names the class, followed by an optional *type_parameter_list* ([§15.2.3](classes.md#1523-type-parameters)), followed by an optional *delimited_parameter_list* ([§15.6.2.1](classes.md#15621-general)), followed by an optional *class_base* specification ([§15.2.4](classes.md#1524-class-base-specification)), followed by an optional set of *type_parameter_constraints_clause*s ([§15.2.5](classes.md#1525-type-parameter-constraints)), followed by a *class_body* ([§15.2.6](classes.md#1526-class-body)), optionally followed by a semicolon.

A class having a required member ([§15.7.1](classes.md#1571-general)) directly (that is, not through inheritance) shall be treated as if it were decorated with the attribute `System.Runtime.CompilerServices.RequiredMemberAttribute` (§RequiredMember).

A class declaration shall not supply *type_parameter_constraints_clause*s unless it also supplies a *type_parameter_list*.

A class declaration that supplies a *type_parameter_list* is a generic class declaration. Additionally, any class nested inside a generic class declaration or a generic struct declaration is itself a generic class declaration, since type arguments for the containing type shall be supplied to create a constructed type ([§8.4](types.md#84-constructed-types)).
Expand Down Expand Up @@ -1070,7 +1072,7 @@ The inherited members of a constructed class type are the members of the immedia

### 15.3.5 The new modifier

A *class_member_declaration* is permitted to declare a member with the same name or signature as an inherited member. When this occurs, the derived class member is said to *hide* the base class member. See [§7.7.2.3](basic-concepts.md#7723-hiding-through-inheritance) for a precise specification of when a member hides an inherited member.
A *class_member_declaration* is permitted to declare a member with the same name or signature as an inherited member. When this occurs, the derived class member is said to *hide* the base class member. However, it is an error to hide a required member ([§15.7.1](classes.md#1571-general)). See [§7.7.2.3](basic-concepts.md#7723-hiding-through-inheritance) for a precise specification of when a member hides an inherited member.

An inherited member `M` is considered to be ***available*** if `M` is accessible and there is no other inherited accessible member N that already hides `M`. Implicitly hiding an inherited member is not considered an error, but a compiler shall issue a warning unless the declaration of the derived class member includes a `new` modifier to explicitly indicate that the derived member is intended to hide the base member. If one or more parts of a partial declaration ([§15.2.7](classes.md#1527-partial-type-declarations)) of a nested type include the `new` modifier, no warning is issued if the nested type hides an available inherited member.

Expand Down Expand Up @@ -1691,6 +1693,7 @@ field_modifier
| 'static'
| 'readonly'
| 'volatile'
| 'required'
| unsafe_modifier // unsafe code support
;

Expand All @@ -1705,7 +1708,7 @@ variable_declarator

*unsafe_modifier* ([§24.2](unsafe-code.md#242-unsafe-contexts)) is only available in unsafe code ([§24](unsafe-code.md#24-unsafe-code)).

A *field_declaration* may include a set of *attributes* ([§23](attributes.md#23-attributes)), a `new` modifier ([§15.3.5](classes.md#1535-the-new-modifier)), a valid combination of the four access modifiers ([§15.3.6](classes.md#1536-access-modifiers)), and a `static` modifier ([§15.5.2](classes.md#1552-static-and-instance-fields)). In addition, a *field_declaration* may include a `readonly` modifier ([§15.5.3](classes.md#1553-readonly-fields)) or a `volatile` modifier ([§15.5.4](classes.md#1554-volatile-fields)), but not both. The attributes and modifiers apply to all of the members declared by the *field_declaration*. It is an error for the same modifier to appear multiple times in a *field_declaration*.
A *field_declaration* may include a set of *attributes* ([§23](attributes.md#23-attributes)), a `new` modifier ([§15.3.5](classes.md#1535-the-new-modifier)), a valid combination of the four access modifiers ([§15.3.6](classes.md#1536-access-modifiers)), and a `static` modifier ([§15.5.2](classes.md#1552-static-and-instance-fields)). In addition, a *field_declaration* may include a `readonly` modifier ([§15.5.3](classes.md#1553-readonly-fields)) or a `volatile` modifier ([§15.5.4](classes.md#1554-volatile-fields)), but not both. A *field_declaration* may also include a `required` modifier ([§15.7.1](classes.md#1571-general)), provided it does not have a `readonly` modifier. The attributes and modifiers apply to all of the members declared by the *field_declaration*. It is an error for the same modifier to appear multiple times in a *field_declaration*.

The *type* of a *field_declaration* specifies the type of the members introduced by the declaration. The type is followed by a list of *variable_declarator*s, each of which introduces a new member. A *variable_declarator* consists of an *identifier* that names that member, optionally followed by an “`=`” token and a *variable_initializer* ([§15.5.6](classes.md#1556-variable-initializers)) that gives the initial value of that member.

Expand Down Expand Up @@ -3401,6 +3404,7 @@ property_modifier
| 'abstract'
| 'extern'
| 'readonly' // struct members only
| 'required'
| unsafe_modifier // unsafe code support
;

Expand Down Expand Up @@ -3448,6 +3452,25 @@ In a *ref_property_body* an expression body consisting of `=>` followed by `ref`

When a property declaration includes an `extern` modifier, the property is said to be an ***external property***. Because an external property declaration provides no actual implementation, each of the *accessor_body*s in its *accessor_declarations* shall be a semicolon.

The modifier `required` indicates the instance member being declared is required to be set during object initialization, which forces the instance creator to provide an initial value for the member in an object initializer at the creation site. (See [§12.8.21](expressions.md#12821-default-value-expressions) and §SetsRequiredMembers for exemptions to this requirement.) A required member shall not be static. A required member shall be at least as accessible as its containing type.

> *Note*: Although a required member declaration may include an initializer (*property_initializer* for a property, *variable_initializer* for a field), ordinarily, that initializer serves no purpose, as the instance creator is required to provide an initial value for that member anyway. However, if a constructor is decorated with the `SetsRequiredMembers` attribute the compiler assumes that member has been initialized correctly, and will not require an explicit initializer by the instance creator, resulting in the member’s initial value being that of its initializer, if one is present. *end note*

A ***required member list*** is a list of all the members of a type that are required. A type automatically inherits this list from its base type.
To build the required member list `R` for a type `T`, the following steps are used:

1. For every type `Tb`, starting with `T` and working through the base type chain until `object` is reached.
1. If `Tb` is decorated with the `RequiredMember` attribute (§RequiredMember), then all members of `Tb` marked with that attribute are gathered into `Rb`

1. For every `Ri` in `Rb`, if `Ri` is overridden by any member of `R`, it is skipped.
1. Otherwise, if any `Ri` is hidden by a member of `R`, then the lookup of required members fails, and no further steps are taken. Calling any constructor of `T` not decorated with the `SetsRequiredMembers` is an error.
1. Otherwise, `Ri` is added to `R`.

A required member shall be treated as if it were decorated with the attribute `System.Runtime.CompilerServices.RequiredMemberAttribute` (§RequiredMember).
With regard to nullable reference type analysis ([§8.9](types.md#89-reference-types-and-nullability)), a required member need not be initialized to a valid nullable state when any of its instance constructors returns. Any required member in a type and its base types is considered by nullable analysis to have its default value at the beginning of any instance constructor in that type, unless it chains to a `this` or `base` constructor that is decorated with the `SetsRequiredMembersAttribute` attribute.

Nullable analysis shall warn about all required members from the current and base types that do not have a valid nullable state at the end of a constructor decorated with the `SetsRequiredMembersAttribute` attribute.

### 15.7.2 Static and instance properties

When a property declaration includes a `static` modifier, the property is said to be a ***static property***. When no `static` modifier is present, the property is said to be an ***instance property***.
Expand Down Expand Up @@ -4242,6 +4265,8 @@ An accessor that is used to implement an interface shall not have an *accessor_m
>
> *end example*

The set or init accessor of a required property ([§15.7.1](classes.md#1571-general)) shall be at least as accessible as that property’s containing type.

### 15.7.6 Virtual, sealed, override, and abstract accessors

*Note*: This subclause applies to both properties ([§15.7](classes.md#157-properties)) and indexers ([§15.9](classes.md#159-indexers)). The subclause is written in terms of properties, when reading for indexers substitute indexer/indexers for property/properties and consult the list of differences between properties and indexers given in [§15.9.2](classes.md#1592-indexer-and-property-differences). *end note*
Expand All @@ -4250,6 +4275,10 @@ A virtual property declaration specifies that the accessors of the property are

An abstract property declaration specifies that the accessors of the property are virtual, but does not provide an actual implementation of the accessors. Instead, non-abstract derived classes are required to provide their own implementation for the accessors by overriding the property. Because an accessor for an abstract property declaration provides no actual implementation, its *accessor_body* simply consists of a semicolon. An abstract property shall not have a `private` accessor.

A property that overrides a base property that is required ([§15.7.1](classes.md#1571-general)) shall itself be required. A property that overrides a base property that is not required may itself be required, in which case, the derived type member is added to that type’s required member list.

> *Note*: A type is permitted to override a required virtual property. This means that if the base virtual property has storage, and the derived type tries to access the base implementation of that property, it could observe uninitialized storage. *end note*

A property declaration that includes both the `abstract` and `override` modifiers specifies that the property is abstract and overrides a base property. The accessors of such a property are also abstract.

Abstract property declarations are only permitted in abstract classes ([§15.2.2.2](classes.md#15222-abstract-classes)) and interfaces ([§19.4.4](interfaces.md#1944-interface-properties)). The accessors of an inherited virtual property can be overridden in a derived class by including a property declaration that specifies an `override` directive. This is known as an ***overriding property declaration***. An overriding property declaration does not declare a new property. Instead, it simply specializes the implementations of the accessors of an existing virtual property.
Expand Down Expand Up @@ -5215,6 +5244,15 @@ Each of the types referenced in the *parameter_list* of an instance constructor

The optional *constructor_initializer* specifies another instance constructor to invoke before executing the statements given in the *constructor_body* of this instance constructor. This is described further in [§15.11.2](classes.md#15112-constructor-initializers).

All instance constructors on a type that has a required member list ([§15.7.1](classes.md#1571-general)) automatically advertise a contract that consumers of the type shall initialize all of the properties in the list. It is an error for an instance constructor to advertise a contract that requires a member that is not at least as accessible as the constructor itself.
An instance constructor whose *constructor_initializer* chains to another constructor decorated with the `SetsRequiredMembers` attribute (§SetsRequiredMembers), shall also be decorated with that attribute.
For every instance constructor `Ci` in type `T` with required members `R`, unless `Ci` is decorated with the attribute `SetsRequiredMembers`consumers, calling `Ci` shall involve one of the following:

- Set all members of `R` in an *object_initializer* on the *object_creation_expression*,
- Or set all members of `R` via the *named_argument_list* of an *attribute*.

If the current context does not permit an *object_initializer* or is not an *attribute* with *named_argument_list*, and `Ci` is not decorated with `SetsRequiredMembers`, then it is an error to call `Ci`.

When a constructor declaration includes an `extern` modifier, the constructor is said to be an ***external constructor***. Because an external constructor declaration provides no actual implementation, its *constructor_body* consists of a semicolon. For all other constructors, the *constructor_body* consists of either

- a *block*, which specifies the statements to initialize a new instance of the class; or
Expand Down Expand Up @@ -5485,6 +5523,8 @@ A ***copy constructor*** for a type `T` is a constructor having a single paramet

In certain circumstances ([§15.16.3](classes.md#15163-copy-and-clone-members)), a copy constructor may be synthesized by the compiler, and called by synthesized code.

A copy constructor on a type that has a required member list ([§15.7.1](classes.md#1571-general)) shall be decorated with the `SetsRequiredMembers` attribute (§SetsRequiredMembers).

## 15.12 Static constructors

A ***static constructor*** is a member that implements the actions required to initialize a closed class. Static constructors are declared using *static_constructor_declaration*s:
Expand Down
19 changes: 19 additions & 0 deletions standard/expressions.md
Original file line number Diff line number Diff line change
Expand Up @@ -3518,6 +3518,25 @@ A *default_value_expression* is a constant expression ([§12.26](expressions.md#
- one of the following value types: `sbyte`, `byte`, `short`, `ushort`, `int`, `uint`, `nint`, `nuint`, `long`, `ulong`, `char`, `float`, `double`, `decimal`, `bool`; or
- any enumeration type.

When an instance of a struct `S` having a required member list ([§15.7.1](classes.md#1571-general)) is created with a value of `default` or `default(S)`, required-member setting is not enforced. However, such setting is enforced for an instance created with `new S()`, even when `S` has no parameterless constructor and the default struct constructor is used.

> *Example*: Consider the following:
>
> <!-- Example: {template:"standalone-console", name:"RequiredMembers", expectedErrors:["CS9035"], expectedWarnings:["CS0219","CS0219","CS0219"]} -->
> ```csharp
> S v1 = default; // OK: no checking for required members
> S v2 = default(S); // OK: no checking for required members
> S v3 = new S(); // error: required member must be set
> S v4 = new S() { reqInt = default }; // OK: required member is set
>
> public struct S
> {
> public required int reqInt;
> }
> ```
>
> *end example*

### 12.8.22 Stack allocation

A stack allocation expression allocates a block of memory from the execution stack. The ***execution stack*** is an area of memory where local variables are stored. The execution stack is not part of the managed heap. The memory used for local variable storage is automatically recovered when the current function returns.
Expand Down
Loading
Loading