You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Closes#1602
- Complete #1560 by covering *foreach_statement* using
a *deconstructor*
- Add sample “Deconstructing foreach”
- Change subclause title from “await foreach” to “Asynchronous
foreach” for consistency with siblings
- Also cleans up some whitespace
The *local_variable_type* and *identifier* of a foreach statement declare the ***iteration variable*** of the statement. If the `var` identifier is given as the *local_variable_type*, and no type named `var` is in scope, the iteration variable is said to be an ***implicitly typed iteration variable***, and its type is taken to be the element type of the `foreach` statement, as specified below.
1121
+
There are three forms of the *foreach_statement*: *synchronous*, *asynchronous* and *deconstructing*; corresponding to the three alternatives of the above grammar.
1122
+
1123
+
The deconstructing foreach supports both synchronous and asynchronous forms and is described in §deconstructing-foreach.
1115
1124
1116
-
It is a compile time error for both `await`and `ref_kind`to be present in a `foreach statement`.
1125
+
The *local_variable_type* and *identifier* of a foreach statement declare the ***iteration variable*** of the statement. If the `var` identifier is given as the *local_variable_type*, and no type named `var` is in scope, the iteration variable is said to be an ***implicitly typed iteration variable***, and its type is taken to be the element type of the `foreach` statement, as specified below.
1117
1126
1118
1127
If the *foreach_statement* contains both or neither `ref` and `readonly`, the iteration variable denotes a variable that is treated as read-only. Otherwise, if *foreach_statement* contains `ref` without `readonly`, the iteration variable denotes a variable that shall be writable.
1119
1128
1120
1129
The iteration variable corresponds to a local variable with a scope that extends over the embedded statement. During execution of a `foreach` statement, the iteration variable represents the collection element for which an iteration is currently being performed. If the iteration variable denotes a read-only variable, a compile-time error occurs if the embedded statement attempts to modify it (via assignment or the `++` and `--` operators) or pass it as a reference or output parameter.
1121
1130
1122
1131
The compile-time processing of a `foreach` statement first determines the ***collection type*** (`C`), ***enumerator type*** (`E`) and ***iteration type*** (`T`, `ref T` or `ref readonly T`) of the expression.
1123
1132
1124
-
The determination is similar for the synchronous and asynchronous versions. Different interfaces with different methods and return types distinguish the synchronous and asynchronous versions. The general process proceeds as follows. Names within ‘«’ and ‘»’ are placeholders for the actual names for synchronous and asynchronous iterators. The types allowed for «GetEnumerator», «MoveNext», «IEnumerable»\<T>, «IEnumerator»\<T>, and any other distinctions are detailed in [§13.9.5.2](statements.md#13952-synchronous-foreach) for a synchronous `foreach` statement, and in [§13.9.5.3](statements.md#13953-await-foreach) for an asynchronous `foreach` statement.
1133
+
The determination is similar for the synchronous and asynchronous versions. Different interfaces with different methods and return types distinguish the synchronous and asynchronous versions. The general process proceeds as follows. Names within ‘«’ and ‘»’ are placeholders for the actual names for synchronous and asynchronous iterators. The types allowed for «GetEnumerator», «MoveNext», «IEnumerable»\<T>, «IEnumerator»\<T>, and any other distinctions are detailed in [§13.9.5.2](statements.md#13952-synchronous-foreach) for a synchronous `foreach` statement, and in [§13.9.5.3](statements.md#13953-asynchronous-foreach) for an asynchronous `foreach` statement.
1125
1134
1126
1135
1. Determine whether the type `X` of *expression* has an appropriate «GetEnumerator» method:
1127
1136
1. Perform member lookup on the type `X` with identifier «GetEnumerator» and no type arguments. If the member lookup does not produce a match, or it produces an ambiguity, or produces a match that is not a method group, check for an enumerable interface as described in step 2. It is recommended that a warning be issued if member lookup produces anything except a method group or no match.
@@ -1137,7 +1146,7 @@ The determination is similar for the synchronous and asynchronous versions. Diff
1137
1146
1138
1147
> *Note*: If *expression* has the value `null`, a `System.NullReferenceException` is thrown at run-time. *end note*
1139
1148
1140
-
An implementation is permitted to implement a given *foreach_statement* differently; e.g., for performance reasons, as long as the behavior is consistent with the expansions described in [§13.9.5.2](statements.md#13952-synchronous-foreach) and [§13.9.5.3](statements.md#13953-await-foreach).
1149
+
An implementation is permitted to implement a given *foreach_statement* differently; e.g., for performance reasons, as long as the behavior is consistent with the expansions described in [§13.9.5.2](statements.md#13952-synchronous-foreach) and [§13.9.5.3](statements.md#13953-asynchronous-foreach).
1141
1150
1142
1151
#### 13.9.5.2 Synchronous foreach
1143
1152
@@ -1166,7 +1175,7 @@ A `foreach` statement of the form
1166
1175
foreach (Vvinx) «embedded_statement»
1167
1176
```
1168
1177
1169
-
is then equivalent to:
1178
+
is semantically equivalent to:
1170
1179
1171
1180
```csharp
1172
1181
{
@@ -1194,7 +1203,7 @@ When the iteration variable is a reference variable ([§9.7](variables.md#97-ref
1194
1203
foreach (refVvinx) «embedded_statement»
1195
1204
```
1196
1205
1197
-
is then equivalent to:
1206
+
is semantically equivalent to:
1198
1207
1199
1208
```csharp
1200
1209
{
@@ -1273,7 +1282,7 @@ The body of the `finally` block is constructed according to the following steps:
1273
1282
```
1274
1283
1275
1284
- Otherwise, the `finally` clause is expanded to:
1276
-
1285
+
1277
1286
```csharp
1278
1287
finally
1279
1288
{
@@ -1336,7 +1345,7 @@ The order in which `foreach` traverses the elements of an array, is as follows:
1336
1345
>
1337
1346
>*endexample*
1338
1347
1339
-
#### 13.9.5.3 await foreach
1348
+
#### 13.9.5.3 Asynchronous foreach
1340
1349
1341
1350
Anasynchronousforeach uses the `await foreach` syntax. The determination of ***collection type***, ***enumeration type*** and ***iteration type*** proceeds as described in [§13.9.5.1](statements.md#13951-general), where:
// dispose of enumerator as described later in this clause.
1366
1381
}
1367
1382
}
1368
-
finally
1369
-
{
1370
-
// dispose of enumerator as described later in this clause.
1371
-
}
1372
1383
```
1373
1384
1374
1385
In the case where the expression `enumerable` represents a method call expression and one of the parameters is marked with the `EnumeratorCancellationAttribute` ([§23.5.8](attributes.md#2358-the-enumeratorcancellation-attribute)) the `CancellationToken` is passed to the `GetAsyncEnumerator` method. Other library methods may require a `CancellationToken` is passed to `GetAsyncEnumerator`. When those methods are part of the expression `enumerable`, the tokens shall be combined into a single token as if by `CreateLinkedTokenSource` and its `Token` property.
@@ -1410,7 +1421,7 @@ The body of the `finally` block is constructed according to the following steps:
1410
1421
```
1411
1422
1412
1423
- Otherwise, the `finally` clause is expanded to:
1413
-
1424
+
1414
1425
```csharp
1415
1426
finally
1416
1427
{
@@ -1426,6 +1437,77 @@ The local variable `d` is not visible to or accessible to any user code. In par
1426
1437
1427
1438
> *Note*: An `await foreach` is not required to dispose of `e` synchronously if an asynchronous dispose mechanism is not available. *end note*
A deconstructing foreach replaces the declaration and initialisation of a single iteration variable per iteration, in the synchronous and asynchronous foreach statements, with a collection of zero or more iteration variables declared per iteration within the *deconstructor*([§12.23.3](expressions.md#12233-deconstructing-assignment)) of a *deconstructing_assignment*.
1443
+
1444
+
All variables assigned to by the *deconstructor* must be declared within the *deconstructor*, it is a compile time error for any *deconstructor_element* to be a *variable_reference*.
... // dispose of enumerator as for synchronous foreach
1468
+
}
1469
+
}
1470
+
```
1471
+
1472
+
this follows the behavior of synchronous foreach ([§13.9.5.2](statements.md#13952-synchronous-foreach)), differing by replacing the delaration and initialisation of a single iteration variable with a *deconstructing_assignment* which declares and assigns zero or more initialisation variables:
1473
+
1474
+
-`C` and `E` are determined as for synchronous foreach
1475
+
-`e` is not visible or accessible anywhere in the program accept as indicated in the above code
1476
+
- the variables declared by the «deconstructor» are read-only to the «embedded_statement»
1477
+
- the code in the `finally` block is determined as for synchronous foreach
// dispose of enumerator as for asynchronous foreach
1501
+
}
1502
+
}
1503
+
```
1504
+
1505
+
this follows the behavior of asynchronous foreach ([§13.9.5.3](statements.md#13953-asynchronous-foreach)), differing by replacing the delaration and initialisation of a single iteration variable with a *deconstructing_assignment* which declares and assigns zero or more initialisation variables:
1506
+
1507
+
-`enumerator` is not visible or accessible anywhere in the program accept as indicated in the above code
1508
+
- the variables declared by the «deconstructor» are read-only to the «embedded_statement»
1509
+
- the code in the `finally` block is determined as for asynchronous foreach
1510
+
1429
1511
## 13.10 Jump statements
1430
1512
1431
1513
### 13.10.1 General
@@ -1813,14 +1895,14 @@ If an exception is thrown during execution of a `finally` block, and is not caug
1813
1895
> {
1814
1896
>Console.WriteLine("Catch");
1815
1897
> }
1816
-
>
1898
+
>
1817
1899
>boolExceptionFilter(Exceptionex)
1818
1900
> {
1819
1901
>Console.WriteLine("Filter");
1820
1902
>returntrue;
1821
1903
> }
1822
1904
> }
1823
-
>
1905
+
>
1824
1906
>staticvoidMethod()
1825
1907
> {
1826
1908
>try
@@ -1945,10 +2027,10 @@ A `using` statement is translated into three parts: acquisition, usage, and disp
1945
2027
A `using` statement of the form
1946
2028
1947
2029
```csharp
1948
-
using (ResourceTyperesource= «expression») «statement»
2030
+
using (ResourceTyperesource= «expression») «statement»
1949
2031
```
1950
2032
1951
-
corresponds to one of three possible formulations. For class and non-ref struct resources, when `ResourceType` is a non-nullable value type or a type parameter with the value type constraint ([§15.2.5](classes.md#1525-type-parameter-constraints)), the formulation is semantically equivalent to
2033
+
corresponds to one of three possible formulations. For class and non-ref struct resources, when `ResourceType` is a non-nullable value type or a type parameter with the value type constraint ([§15.2.5](classes.md#1525-type-parameter-constraints)), the formulation is semantically equivalent to:
1952
2034
1953
2035
```csharp
1954
2036
{
@@ -2080,16 +2162,16 @@ using (ResourceType rN = eN)
2080
2162
When `ResourceType` is a reference type that implements `IAsyncDisposable`. Other formulations for `await using` perform similar substitutions from the synchronous `Dispose` method to the asynchronous `DisposeAsync` method. An `await using` statement of the form
2081
2163
2082
2164
```csharp
2083
-
await using (ResourceType resource = «expression») «statement»
2165
+
await using (ResourceType resource = «expression») «statement»
2084
2166
```
2085
2167
2086
2168
is semantically equivalent to the formulations shown below with `IAsyncDisposable` instead of `IDisposable`, `DisposeAsync` instead of `Dispose`, and the `Task` returned from `DisposeAsync` is `await`ed:
2087
2169
2088
2170
```csharp
2089
-
await using (ResourceType resource = «expression») «statement»
2171
+
await using (ResourceType resource = «expression») «statement»
2090
2172
```
2091
2173
2092
-
is semantically equivalent to
2174
+
is semantically equivalent to:
2093
2175
2094
2176
```csharp
2095
2177
{
@@ -2128,7 +2210,7 @@ using «local_variable_type» «local_variable_declarators»
2128
2210
// statements
2129
2211
```
2130
2212
2131
-
issemanticallyequivalentto
2213
+
issemanticallyequivalentto:
2132
2214
2133
2215
```csharp
2134
2216
using («local_variable_type» «local_variable_declarators»)
@@ -2144,7 +2226,7 @@ await using «local_variable_type» «local_variable_declarators»
0 commit comments