Skip to content
Draft
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
9 changes: 5 additions & 4 deletions standard/classes.md
Original file line number Diff line number Diff line change
Expand Up @@ -422,7 +422,7 @@
: 'where' type_parameter ':' type_parameter_constraints
;

type_parameter_constraints

Check warning on line 425 in standard/classes.md

View workflow job for this annotation

GitHub Actions / Markdown to Word Converter

standard/classes.md#L425

MDC032::Line length 83 > maximum 81
: primary_constraint (',' secondary_constraints)? (',' constructor_constraint)?
| secondary_constraints (',' constructor_constraint)?
| constructor_constraint
Expand Down Expand Up @@ -534,15 +534,15 @@
> static void M()
> {
> // nonnull constraint allows nonnullable struct type argument
> A<int> x1;

Check warning on line 537 in standard/classes.md

View workflow job for this annotation

GitHub Actions / Markdown to Word Converter

standard/classes.md#L537

MDC032::Line length 87 > maximum 81
> // possible warning: nonnull constraint prohibits nullable struct type argument
> A<int?> x2;
> // nonnull constraint allows nonnullable class type argument
> A<C> x3;

Check warning on line 541 in standard/classes.md

View workflow job for this annotation

GitHub Actions / Markdown to Word Converter

standard/classes.md#L541

MDC032::Line length 86 > maximum 81
> // possible warning: nonnull constraint prohibits nullable class type argument
> A<C?> x4;

Check warning on line 543 in standard/classes.md

View workflow job for this annotation

GitHub Actions / Markdown to Word Converter

standard/classes.md#L543

MDC032::Line length 84 > maximum 81
> // nonnullable base class requirement allows nonnullable class type argument
> B1<C> x5;

Check warning on line 545 in standard/classes.md

View workflow job for this annotation

GitHub Actions / Markdown to Word Converter

standard/classes.md#L545

MDC032::Line length 82 > maximum 81
> // possible warning: nonnullable base class requirement prohibits nullable
> // class type argument
> B1<C?> x6;
Expand Down Expand Up @@ -3556,7 +3556,7 @@
> static void Main()
> {
> field = 10;
> Console.WriteLine(Property); // Prints 10

Check warning on line 3559 in standard/classes.md

View workflow job for this annotation

GitHub Actions / Markdown to Word Converter

standard/classes.md#L3559

MDC032::Line length 83 > maximum 81
> Property = 20; // This invokes the get accessor, then assigns
> // via the resulting variable reference
> Console.WriteLine(field); // Prints 20
Expand Down Expand Up @@ -4917,7 +4917,7 @@
: '!'
;

overloadable_unary_operator

Check warning on line 4920 in standard/classes.md

View workflow job for this annotation

GitHub Actions / Markdown to Word Converter

standard/classes.md#L4920

MDC032::Line length 82 > maximum 81
: '+' | '-' | logical_negation_operator | '~' | '++' | '--' | 'true' | 'false'
;

Expand Down Expand Up @@ -5272,7 +5272,11 @@

### 15.11.3 Instance variable initializers

When a non-extern instance constructor has no constructor initializer, or it has a constructor initializer of the form `base(...)`, that constructor implicitly performs the initializations specified by the *variable_initializer*s of the instance fields declared in its class. This corresponds to a sequence of assignments that are executed immediately upon entry to the constructor and before the implicit invocation of the direct base class constructor. The variable initializers are executed in the textual order in which they appear in the class declaration ([§15.5.6](classes.md#1556-variable-initializers)).
When a non-extern class instance constructor has no constructor initializer, or it has a constructor initializer of the form `base(...)`, that constructor implicitly performs the initializations specified by the *variable_initializer*s of the instance fields declared in its class. This corresponds to a sequence of assignments that are executed immediately upon entry to the constructor and before the implicit invocation of the direct base class constructor. The variable initializers are executed in the textual order in which they appear in the class declaration ([§15.5.6](classes.md#1556-variable-initializers)).

When a struct instance constructor has no constructor initializer, that constructor implicitly performs the initializations specified by the *variable_initializer*s of the instance fields declared in its struct. This corresponds to a sequence of assignments that are executed immediately upon entry to the constructor.

When a struct instance constructor has a `this()` constructor initializer that represents the *default parameterless constructor*, the declared constructor implicitly clears all instance fields and performs the initializations specified by the *variable_initializer*s of the instance fields declared in its struct. Immediately upon entry to the constructor, all value type fields are set to their default value and all reference type fields are set to `null`. Immediately after that, a sequence of assignments corresponding to the *variable_initializer*s are executed.

Variable initializers are not required to be executed by extern instance constructors.

Expand Down Expand Up @@ -6134,7 +6138,7 @@
> public static bool operator!=(R1? left, R1? right) => !(left == right);
>
> public override int GetHashCode()
> {

Check warning on line 6141 in standard/classes.md

View workflow job for this annotation

GitHub Actions / Markdown to Word Converter

standard/classes.md#L6141

MDC032::Line length 93 > maximum 81
> return HashCode.Combine(EqualityComparer<Type>.Default.GetHashCode(EqualityContract),
> EqualityComparer<T1>.Default.GetHashCode(P1));
> }
Expand Down Expand Up @@ -6315,7 +6319,7 @@
> protected virtual bool PrintMembers(StringBuilder builder)
> {
> builder.Append(nameof(P1));
> builder.Append(" = ");

Check warning on line 6322 in standard/classes.md

View workflow job for this annotation

GitHub Actions / Markdown to Word Converter

standard/classes.md#L6322

MDC032::Line length 97 > maximum 81
> builder.Append(this.P1); // or builder.Append(this.P1.ToString()); if P1 has a value type
> return true;
> }
Expand Down Expand Up @@ -6346,11 +6350,11 @@
> builder.Append(", ");
> }
> builder.Append(nameof(P2));
> builder.Append(" = ");

Check warning on line 6353 in standard/classes.md

View workflow job for this annotation

GitHub Actions / Markdown to Word Converter

standard/classes.md#L6353

MDC032::Line length 86 > maximum 81
> builder.Append(this.P2); // or builder.Append(this.P2); if P2 has a value type
> builder.Append(", ");
> builder.Append(nameof(P3));
> builder.Append(" = ");

Check warning on line 6357 in standard/classes.md

View workflow job for this annotation

GitHub Actions / Markdown to Word Converter

standard/classes.md#L6357

MDC032::Line length 86 > maximum 81
> builder.Append(this.P3); // or builder.Append(this.P3); if P3 has a value type
> return true;
> }
Expand Down Expand Up @@ -6483,6 +6487,3 @@
> ```
>
> *end example*



60 changes: 44 additions & 16 deletions standard/structs.md
Original file line number Diff line number Diff line change
Expand Up @@ -150,8 +150,6 @@ Structs differ from classes in several important ways:
- The default value of a struct is the value produced by setting all fields to their default value ([§16.4.5](structs.md#1645-default-values)).
- Boxing and unboxing operations are used to convert between a struct type and certain reference types ([§16.4.6](structs.md#1646-boxing-and-unboxing)).
- The meaning of `this` is different within struct members ([§16.4.7](structs.md#1647-meaning-of-this)).
- Instance field declarations for a struct are not permitted to include variable initializers ([§16.4.8](structs.md#1648-field-initializers)).
- A struct is not permitted to declare a parameterless instance constructor ([§16.4.9](structs.md#1649-constructors)).
- A struct is not permitted to declare a finalizer.
- Event declarations, property declarations, property accessors, indexer declarations, and method declarations are permitted to have the modifier `readonly` while that is not generally permitted for those same member kinds in classes.

Expand Down Expand Up @@ -385,64 +383,94 @@ Similarly, boxing never implicitly occurs when accessing a member on a constrain

### 16.4.8 Field initializers

As described in [§16.4.5](structs.md#1645-default-values), the default value of a struct consists of the value that results from setting all value type fields to their default value and all reference type fields to `null`. For this reason, a struct does not permit instance field declarations to include variable initializers. This restriction applies only to instance fields. Static fields of a struct are permitted to include variable initializers.
As described in [§16.4.5](structs.md#1645-default-values), the default value of a struct consists of the value that results from setting all value type fields to their default value and all reference type fields to `null`. Static and instance fields of a struct are permitted to include variable initializers; however, in the case of an instance field initializer, at least one instance constructor shall also be declared, or for a record struct, a *delimited_parameter_list* shall be present.

> *Example*: The following
> *Example*:
>
> <!-- Example: {template:"standalone-lib-without-using", name:"FieldInitializers", expectedErrors:["CS8983"], ignoredWarnings:["CS0649"]} -->
> <!-- Example: {template:"standalone-console", name:"FieldInitializers", inferOutput:true} -->
> ```csharp
> Console.WriteLine($"Point is {new Point()}");
>
> struct Point
> {
> public int x = 1; // Error, initializer not permitted
> public int y = 1; // Error, initializer not permitted
> public int x = 1;
> public int y = 1;
>
> public Point() { }
>
> public override string ToString()
> {
> return "(" + x + ", " + y + ")";
> }
> }
> ```
>
> is in error because the instance field declarations include variable initializers.
> ```console
> Point is (1, 1)
> ```
>
> *end example*

When a struct instance constructor has no constructor initializer, that constructor implicitly performs the initializations specified by the *variable_initializer*s of the instance fields declared in its struct. This corresponds to a sequence of assignments that are executed immediately upon entry to the constructor.

When a struct instance constructor has a `this()` constructor initializer that represents the default parameterless constructor, the declared constructor implicitly clears all instance fields and performs the initializations specified by the *variable_initializer*s of the instance fields declared in its struct. Immediately upon entry to the constructor, all value type fields are set to their default value and all reference type fields are set to `null`. Immediately after that, a sequence of assignments corresponding to the *variable_initializer*s are executed.

A *field_declaration* declared directly inside a *struct_declaration* having the *struct_modifier* `readonly` shall have the *field_modifier* `readonly`.

### 16.4.9 Constructors

Unlike a class, a struct is not permitted to declare a parameterless instance constructor. Instead, every struct implicitly has a parameterless instance constructor, which always returns the value that results from setting all value type fields to their default value and all reference type fields to `null` ([§8.3.3](types.md#833-default-constructors)). A struct can declare instance constructors having parameters.
A struct can declare instance constructors, with zero or more parameters. If a struct has no explicitly declared parameterless instance constructor, one is synthesized, with public accessibility, which always returns the value that results from setting all value type fields to their default value and all reference type fields to `null` ([§8.3.3](types.md#833-default-constructors)). In such a case, any instance field initializers are ignored when that constructor executes.

> *Example*: Given the following
An explicitly declared parameterless instance constructor shall have public accessibility.

> *Example*: Given the following:
>
> <!-- Example: {template:"standalone-console-without-using", name:"Constructors1", ignoredWarnings:["CS0219"]} -->
> <!-- Example: {template:"standalone-console", name:"Constructors1", ignoredWarnings:["CS0219"], inferOutput:true} -->
> ```csharp
> using System;
> struct Point
> {
> int x, y;
> int x = -1, y = -2;
>
> public Point(int x, int y)
> {
> this.x = x;
> this.y = y;
> }
>
> public override string ToString()
> {
> return "(" + x + ", " + y + ")";
> }
> }
>
> class A
> {
> static void Main()
> {
> Point p1 = new Point();
> Point p2 = new Point(0, 0);
> Console.WriteLine($"Point is {new Point()}");
> Console.WriteLine($"Point is {new Point(0,0)}");
> }
> }
> ```
>
> the statements both create a `Point` with `x` and `y` initialized to zero.
> ```console
> Point is (0, 0)
> Point is (0, 0)
> ```
>
> the statements both create a `Point` with `x` and `y` initialized to zero, which in the case of the call to the parameterless instance constructor, may be surprising, as both instance fields have initializers, but they are *not* executed.
>
> *end example*

A struct instance constructor is not permitted to include a constructor initializer of the form `base(`*argument_list*`)`, where *argument_list* is optional.
A struct instance constructor is not permitted to include a constructor initializer of the form `base(`*argument_list*`)`, where *argument_list* is optional. The execution of an instance constructor shall not result in the execution of a constructor in the struct’s base type `System.ValueType`.

The `this` parameter of a struct instance constructor corresponds to an output parameter of the struct type. As such, `this` shall be definitely assigned ([§9.4](variables.md#94-definite-assignment)) at every location where the constructor returns. Similarly, it cannot be read (even implicitly) in the constructor body before being definitely assigned.

If the struct instance constructor specifies a constructor initializer, that initializer is considered a definite assignment to this that occurs prior to the body of the constructor. Therefore, the body itself has no initialization requirements.

Instance fields (other than `fixed` fields) shall be definitely assigned in struct instance constructors that do not have a `this()` initializer.

> *Example*: Consider the instance constructor implementation below:
>
> <!-- Example: {template:"standalone-lib-without-using", name:"Constructors2", expectedErrors:["CS0188"]} -->
Expand Down
Loading