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
11 changes: 11 additions & 0 deletions standard/attributes.md
Original file line number Diff line number Diff line change
Expand Up @@ -512,6 +512,7 @@ A number of attributes affect the language in some way. These attributes include
- `System.Runtime.CompilerServices.InterpolatedStringHandlerAttribute` and `System.Runtime.CompilerServices.InterpolatedStringHandlerArgumentAttribute`, which are used to declare a custom interpolated string expression handler ([§23.5.11.1](attributes.md#235111-custom-interpolated-string-expression-handlers)) and to call one of its constructors, respectively.
- `System.Diagnostics.CodeAnalysis.UnscopedRefAttribute` ([§23.5.8](attributes.md#2358-the-unscopedref-attribute)), which allows an otherwise implicitly scoped ref to be treated as not being scoped.
- `System.Diagnostics.CodeAnalysis.SetsRequiredMembersAttribute` ([§23.5.12.1](attributes.md#235121-the-setsrequiredmembers-attribute)) and `System.Runtime.CompilerServices.RequiredMemberAttribute` ([§23.5.12.2](attributes.md#235122-the-requiredmember-attribute)), which are used in required-member contexts ([§15.7.1](classes.md#1571-general)).
- `System.Runtime.CompilerServices.CollectionBuilderAttribute` (§collection-builder-attr), which designates a collection type as having a collection-creation method.

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 @@ -1577,6 +1578,16 @@ This attribute indicates that the constructor it decorates sets all required mem

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.

### §collection-builder-attr The CollectionBuilder attribute

This attribute designates a collection type as having a collection-creation method (§declaring-a-collection-type-general).

The constructor takes a builder type and the name of the method to be invoked to construct an instance of the collection type.

The attribute can be applied to a class, struct, ref struct, or interface. The attribute is not inherited although it can be applied to a base class or an abstract class.

The builder type shall be a non-generic class or struct.

## 23.6 Attributes for interoperation

For interoperation with other languages, an indexer may be implemented using indexed properties. If the indexer is not decorated with `IndexerNameAttribute`, then the name `Item` is used by default. `IndexerNameAttribute` enables a developer to override this default and specify a different name.
Expand Down
157 changes: 156 additions & 1 deletion standard/classes.md
Original file line number Diff line number Diff line change
@@ -1,24 +1,24 @@
# 15 Classes

Check warning on line 2 in standard/classes.md

View workflow job for this annotation

GitHub Actions / Markdown to Word Converter

standard/classes.md#L2

MDC032::Line length 83 > maximum 81
## 15.1 General

Check warning on line 3 in standard/classes.md

View workflow job for this annotation

GitHub Actions / Markdown to Word Converter

standard/classes.md#L3

MDC032::Line length 88 > maximum 81

A class is a data structure that may contain data members (constants and fields), function members (methods, properties, events, indexers, operators, instance constructors, finalizers, and static constructors), and nested types. Class types support inheritance, a mechanism whereby a ***derived class*** can extend and specialize a ***base class***.

Check warning on line 6 in standard/classes.md

View workflow job for this annotation

GitHub Actions / Markdown to Word Converter

standard/classes.md#L6

MDC032::Line length 83 > maximum 81
Structs ([§16](structs.md#16-structs)) and interfaces ([§19](interfaces.md#19-interfaces)) have members similar to classes but with certain restrictions. This clause defines the declarations for classes and class members. The clauses for structs and interfaces define the restrictions for those types in terms of the corresponding declarations in class types.

## 15.2 Class declarations

Check warning on line 9 in standard/classes.md

View workflow job for this annotation

GitHub Actions / Markdown to Word Converter

standard/classes.md#L9

MDC032::Line length 97 > maximum 81

Check warning on line 10 in standard/classes.md

View workflow job for this annotation

GitHub Actions / Markdown to Word Converter

standard/classes.md#L10

MDC032::Line length 83 > maximum 81
### 15.2.1 General

Check warning on line 12 in standard/classes.md

View workflow job for this annotation

GitHub Actions / Markdown to Word Converter

standard/classes.md#L12

MDC032::Line length 87 > maximum 81
A *class_declaration* is a *type_declaration* ([§14.8](namespaces.md#148-type-declarations)) that declares a new class.

```ANTLR
class_declaration

Check warning on line 16 in standard/classes.md

View workflow job for this annotation

GitHub Actions / Markdown to Word Converter

standard/classes.md#L16

MDC032::Line length 86 > maximum 81
: non_record_class_declaration
| record_class_declaration

Check warning on line 18 in standard/classes.md

View workflow job for this annotation

GitHub Actions / Markdown to Word Converter

standard/classes.md#L18

MDC032::Line length 84 > maximum 81
;

Check warning on line 20 in standard/classes.md

View workflow job for this annotation

GitHub Actions / Markdown to Word Converter

standard/classes.md#L20

MDC032::Line length 82 > maximum 81
non_record_class_declaration

Check warning on line 21 in standard/classes.md

View workflow job for this annotation

GitHub Actions / Markdown to Word Converter

standard/classes.md#L21

MDC032::Line length 93 > maximum 81
: attributes? class_modifier* 'partial'? 'class' identifier
type_parameter_list? class_base? type_parameter_constraints_clause*
class_body
Expand All @@ -27,7 +27,7 @@

There are two kinds of class: ***non-record class***, as declared by *non_record_class_declaration*, and ***record class***, as declared by *record_class_declaration*. A non-record class is the kind of class that C# has supported since the language’s inception. Record classes were added much later and are discussed in [§15.16](classes.md#1516-record-classes). The differences between the two kinds are discussed in [§15.17](classes.md#1517-record-class-and-non-record-class-differences).

A *non_record_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 the keyword `class` 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 *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)).

Check warning on line 30 in standard/classes.md

View workflow job for this annotation

GitHub Actions / Markdown to Word Converter

standard/classes.md#L30

MDC032::Line length 115 > maximum 81

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` ([§23.5.12.2](attributes.md#235122-the-requiredmember-attribute)).

Expand All @@ -37,11 +37,11 @@

### 15.2.2 Class modifiers

#### 15.2.2.1 General

Check warning on line 40 in standard/classes.md

View workflow job for this annotation

GitHub Actions / Markdown to Word Converter

standard/classes.md#L40

MDC032::Line length 86 > maximum 81

A *class_declaration* may optionally include a sequence of class modifiers:

```ANTLR

Check warning on line 44 in standard/classes.md

View workflow job for this annotation

GitHub Actions / Markdown to Word Converter

standard/classes.md#L44

MDC032::Line length 86 > maximum 81
class_modifier
: 'new'
| 'public'
Expand Down Expand Up @@ -2546,6 +2546,8 @@
> F(arr);
> F(10, 20, 30, 40);
> F();
> F([-5, 3, 9]);
> F([]);
> }
> }
> ```
Expand All @@ -2556,6 +2558,8 @@
> Array contains 3 elements: 1 2 3
> Array contains 4 elements: 10 20 30 40
> Array contains 0 elements:
> Array contains 3 elements: -5 3 9
> Array contains 0 elements:
> ```
>
> The first invocation of `F` simply passes the array `arr` as a value parameter. The second invocation of F automatically creates a four-element `int[]` with the given element values and passes that array instance as a value parameter. Likewise, the third invocation of `F` creates a zero-element `int[]` and passes that instance as a value parameter. The second and third invocations are precisely equivalent to writing:
Expand All @@ -2565,7 +2569,7 @@
> F(new int[] {});
> ```
>
> *end example*
> The fourth and fifth invocations pass a three-element and an empty collection expression, respectively. *end example*

When performing overload resolution, a method with a parameter array might be applicable, either in its normal form or in its expanded form ([§12.6.4.2](expressions.md#12642-applicable-function-member)). The expanded form of a method is available only if the normal form of the method is not applicable and only if an applicable method with the same signature as the expanded form is not already declared in the same type.

Expand Down Expand Up @@ -6799,6 +6803,157 @@
>
> *end example*

## §declaring-a-collection-type Declaring a collection type

### §declaring-a-collection-type-general General

There are a number of contexts in which a collection expression (§collection-expressions) may be converted to a collection type (§imp-collection-expression-conv). One of them is for a target class, struct, or interface type to be made a collection type by annotating it with an attribute, as shown below.

Here is a simple user-defined collection type and its associated builder type:

<!-- Example: {template:"standalone-lib", name:"CollectionType1"} -->
```csharp
[CollectionBuilder(typeof(MyCollectionBuilder), "Create")]
public class MyCollection<T> : IEnumerable<T>
{
private readonly T[] _storage;
public int Count { get; }
public T this[int index]
{
get
{
return _storage[index];
}

set
{
_storage[index] = value;
}
}
public MyCollection(ReadOnlySpan<T> elements)
{
Count = elements.Length;
_storage = new T[Count];
for (int i = 0; i < Count; i++)
{
_storage[i] = elements[i];
}
}
public IEnumerator<T> GetEnumerator() =>
((IEnumerable<T>)_storage).GetEnumerator();
IEnumerator IEnumerable.GetEnumerator() =>
_storage.GetEnumerator();
}
internal static class MyCollectionBuilder
{
internal static MyCollection<T>
Create<T>(ReadOnlySpan<T> values) =>
new MyCollection<T>(values);
}
```

The collection type shall be annotated with `CollectionBuilderAttribute` (§collection-builder-attr) that designates an associated, non-generic builder class or struct type having a collection-creation method (whose name is user-defined; in this case, it is `Create`).

The job of a ***collection-creation method*** is to create and initialize an instance of its associated collection type.

First, the set of applicable collection-creation methods `CM` is determined. It consists of methods that meet the following requirements:

- Be directly declared in the builder type
- Be static
- Be accessible at its point of use
- Its arity shall match that of the collection type
- It shall have a single parameter of type `System.ReadOnlySpan<E>`, passed by value.
- There shall be an implicit identity conversion ([§10.2.2](conversions.md#1022-identity-conversion)), an implicit reference conversion ([§10.2.8](conversions.md#1028-implicit-reference-conversions)), or a boxing conversion ([§10.2.9](conversions.md#1029-boxing-conversions)) from the method return type to the collection type.
- It shall return an instance of the collection being built, which contains a copy of the data from the span parameter.

Methods declared on base types or interfaces are ignored and not part of the `CM` set.

If the `CM` set is empty, then the collection type doesn't have an element type, doesn't have a collection-creation method, and none of the following steps apply.

If only one method among those in the `CM` set has an identity conversion from `E` to the element type of the collection type, that is the collection-creation method for the collection type. Otherwise, the collection type doesn't have a collection-creation method.

It is an error if `CollectionBuilderAttribute` does not refer to an invokable method with the expected signature.

For a *collection_expression* with a target type `C<S₀, S₁, …>` where the type declaration `C<T₀, T₁, …>` has an associated collection-creation method `B.M<U₀, U₁, …>()`, the generic type arguments from the target type are applied in order (from outermost containing type to innermost) to the collection-creation method.

The span parameter for the collection-creation method may be explicitly marked `scoped` or `[UnscopedRef] ([§9.7.3](variables.md#973-the-scoped-modifier))`. If the parameter is implicitly or explicitly `scoped`, the compiler may allocate the storage for the span on the stack rather than the heap.

The construction of an instance of a collection type is described in §collection-construction.

### §collection-construction Collection construction

The *collection_element*s of a *collection_expression* are evaluated in order, left to right. Each *collection_element* is evaluated exactly once, and any further references to the any elements refer to the results of this initial evaluation.

A *spread_element* may be iterated before or after the subsequent elements in the *collection_expression* are evaluated.

An unhandled exception thrown from any of the methods used during construction shall go uncaught and shall prevent further steps in the construction.

`Length`, `Count`, and `GetEnumerator` are assumed to have no side effects.

If the target type is a struct or class type that implements `System.Collections.IEnumerable`, and the target type does not have a collection-creation method (§declaring-a-collection-type-general), the construction of the collection instance steps are, as follows:

- The elements are evaluated in order. Some or all elements may be evaluated during the steps below rather than before.
- The compiler may determine the known length of the collection expression by invoking countable properties ([§18.1](ranges.md#181-general)) or equivalent properties from well-known interfaces or types, on each *spread_element*’s *expression*.
- The constructor that is applicable with no arguments is invoked.
- For each *collection_element*, in order:

- If the *collection_element* is an *expression_element*, the applicable `Add` instance or extension method is invoked with the *element_expression* as the argument. (Unlike classic collection initializer behavior ([§12.8.17.2.3](expressions.md#1281723-collection-initializers)), element evaluation and `Add` calls are not necessarily interleaved.)
- If the *collection_element* is a *spread_element* then one of the following steps is used:

- An applicable `GetEnumerator` instance or extension method is invoked on the *spread_element*’s *expression*, and for each item from the enumerator the applicable `Add` instance or extension method is invoked on the collection instance with the item as the argument. If the enumerator implements `IDisposable`, then `Dispose` shall be called after enumeration, regardless of any exceptions.
- An applicable `AddRange` instance or extension method is invoked on the collection instance with the *spread_element*’s *expression* as the argument.
- An applicable `CopyTo` instance or extension method is invoked on the *spread_element*’s *expression* with the collection instance and `int` index as arguments.

- During the construction steps above, an applicable `EnsureCapacity` instance or extension method may be invoked one or more times on the collection instance with an `int` capacity argument.

If the target type is an array, a `Span` or `ReadOnlySpan`, a type with a collection-creation method, or an interface, the construction steps of the collection instance are, as follows:

- The elements are evaluated in order. Some or all elements may be evaluated during the steps below rather than before.
- The compiler may determine the known length of the collection expression by invoking countable properties (or equivalent properties from well-known interfaces or types) on each *spread_element*’s *expression*.

- An *initialization instance* is created as follows:

- If the target type is an array and the collection expression has a known length, an array is allocated with the expected length.
- If the target type is a `Span` or `ReadOnlySpan`, or a type with a collection-creation method, and the collection has a known length, a `Span` or `ReadOnlySpan` with the expected length is created referring to contiguous storage.
- Otherwise, intermediate storage is allocated.

- For each *collection_element*, in order:

- If the *collection_element*is an *expression_element*, the initialization instance indexer is invoked to add the evaluated expression at the current index.
- If the element is a *spread_element* then one of the following is used:

- A member of a well-known interface or type is invoked to copy items from the spread element expression to the initialization instance.
- An applicable `GetEnumerator` instance or extension method is invoked on the *spread_element*’s *expression*, and for each item from the enumerator, the initialization instance indexer is invoked to add the item at the current index. If the enumerator implements `IDisposable`, then `Dispose` shall be called after enumeration, regardless of any exceptions.
- An applicable `CopyTo` instance or extension method is invoked on the *spread_element*’s *expression* with the initialization instance and `int` index as arguments.

- If intermediate storage was allocated for the collection, a collection instance is allocated with the actual collection length and the values from the initialization instance are copied to the collection instance, or if a span is required the compiler may use a span of the actual collection length from the intermediate storage. Otherwise, the initialization instance is the collection instance.
- If the target type has a collection-creation method, that method is invoked with the span instance.

> *Note:* The compiler might delay adding elements to the collection (or delay iterating through *spread_element*s) until after evaluating subsequent elements. (When subsequent *spread_element*s have countable properties that would allow calculating the expected length of the collection before allocating the collection.) Conversely, the compiler might eagerly add elements to the collection (and eagerly iterate through *spread_element*s) when there is no advantage to delaying.
>
> Consider the following collection expression:
>
> ```csharp
> int[] x = [a, ..b, ..c, d];
> ```
>
> If *spread_element*s `b` and `c` are countable, the compiler could delay adding items from `a` and `b` until after `c` is evaluated, to allow allocating the resulting array at the expected length. After that, the compiler could eagerly add items from `c`, before evaluating `d`, as shown below.
>
> ```csharp
> var __tmp1 = a;
> var __tmp2 = b;
> var __tmp3 = c;
> var __result = new int[2 + __tmp2.Length + __tmp3.Length];
> int __index = 0;
> __result[__index++] = __tmp1;
> foreach (var __i in __tmp2) __result[__index++] = __i;
> foreach (var __i in __tmp3) __result[__index++] = __i;
> __result[__index++] = d;
> x = __result;
> ```
>
> *end note*

## 15.17 Record class and non-record class differences

A record class differs from a non-record class in several important ways:
Expand Down
46 changes: 46 additions & 0 deletions standard/conversions.md
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@
> ```csharp
> enum Color { Red, Blue, Green }
>
> // The expression 0 converts implicitly to enum types

Check warning on line 28 in standard/conversions.md

View workflow job for this annotation

GitHub Actions / Markdown to Word Converter

standard/conversions.md#L28

MDC032::Line length 82 > maximum 81
> Color c0 = 0;
>
> // Other int expressions need explicit conversion
Expand Down Expand Up @@ -460,6 +460,52 @@
>
> *end example*

### §imp-collection-expression-conv Implicit collection expression conversions

An implicit collection expression conversion exists from a collection expression to the following types:

- A single-dimensional array type `T[]`, in which case, the element type is `T`.
- `System.Span<T>` and `System.ReadOnlySpan<T>`, in which cases, the element type is `T`.
- A type with an appropriate collection-creation method (§declaring-a-collection-type-general), in which case, the element type is the iteration type ([§13.9.5](statements.md#1395-the-foreach-statement)) determined from a `GetEnumerator` instance method or enumerable interface, not from an extension method.
- A struct or class type that implements `System.Collections.IEnumerable` where:

- The type has an applicable ([§12.6.4.2](expressions.md#12642-applicable-function-member)) constructor that can be invoked with no arguments, and the constructor is accessible at the location of the collection expression.
- If the collection expression has any elements, the type has an instance or extension method `Add` where:

- The method can be invoked with a single value argument.
- If the method is generic, the type arguments can be inferred from the collection and argument.
- The method is accessible at the location of the collection expression.

In which case, the element type is the iteration type of the type.
- Any of the following interface types:

- `System.Collections.Generic.IEnumerable<T>`
- `System.Collections.Generic.IReadOnlyCollection<T>`
- `System.Collections.Generic.IReadOnlyList<T>`
- `System.Collections.Generic.ICollection<T>`
- `System.Collections.Generic.IList<T>`

in which case, the element type is `T`

The implicit conversion exists if the type has an element type `U` where for each element `Eᵢ` in the collection expression:

- If `Eᵢ` is an *expression_element*, there is an implicit conversion from `Eᵢ` to `U`.
- If `Eᵢ` is a *spread_element* `..Sᵢ`, there is an implicit conversion from the *iteration type* of `Sᵢ` to `U`.

There is no collection expression conversion from a collection expression to a multi-dimensional array type.

Types for which there is an implicit collection expression conversion from a collection expression are the valid target types for that collection expression.

The following additional implicit conversions exist from a collection expression:

- To a nullable value type `T?` where there is a collection expression conversion from the collection expression to the value type `T`. The conversion is a collection expression conversion to `T` followed by an implicit nullable conversion from `T` to `T?`.

- To a reference type `T` where there is a collection-creation method associated with `T` that returns a type `U` and there is an implicit reference conversion from `U` to `T`. The conversion is a collection expression conversion to `U` followed by an implicit reference conversion from `U` to `T`.

- To an interface type `I` where there is a collection-creation method associated with `I` that returns a type `V` and there is an implicit boxing conversion from `V` to `I`. The conversion is a collection expression conversion to `V` followed by an implicit boxing conversion from `V` to `I`.

When a collection expression is converted to a ref struct type, all ref safety requirements ([§9.7.2](variables.md#972-ref-safe-contexts), [§16.6.15](structs.md#16615-safe-context-constraint)) shall be met.

## 10.3 Explicit conversions

### 10.3.1 General
Expand Down
Loading
Loading