Conversation
| - If the type `X` of *expression* is `dynamic` or an array type, then an error is produced and no further steps are taken. | ||
| - Otherwise, determine whether the type `X` has an appropriate `GetAsyncEnumerator` method: | ||
| - Perform member lookup on the type `X` with identifier `GetAsyncEnumerator` 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 below. | ||
| - Perform overload resolution using the resulting method group and an empty argument list. If overload resolution results in no applicable methods, results in an ambiguity, or results in a single best method but that method is either static or not public, check for an enumerable interface as described below. |
There was a problem hiding this comment.
Should a warning be reported if the match is not a method group or is ambiguous or is non-public, similar to the recommendations in foreach-statement? #ByDesign
There was a problem hiding this comment.
LDM said that we don't usually spec warnings, so that's why I didn't include this.
| If the iterated type doesn't expose the right pattern, the interfaces will be used. | ||
| The body of the `finally` block is constructed according to the following steps: | ||
| - If the type `E` has an appropriate `DisposeAsync` method: | ||
| - Perform member lookup on the type `E` with identifier `DisposeAsync` 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 the disposal interface as described below. |
There was a problem hiding this comment.
I'm trying to go for parallel with "enumeration interfaces".
"disposal" and "enumeration" are nouns, but "disposable" and "enumerable" are adjectives?
| The body of the `finally` block is constructed according to the following steps: | ||
| - If the type `E` has an appropriate `DisposeAsync` method: | ||
| - Perform member lookup on the type `E` with identifier `DisposeAsync` 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 the disposal interface as described below. | ||
| - Perform overload resolution using the resulting method group and an empty argument list. If overload resolution results in no applicable methods, results in an ambiguity, or results in a single best method but that method is either static or not public, check for the disposal interface as described below. |
| } | ||
| ``` | ||
| except that if `E` is a value type, or a type parameter instantiated to a value type, then the conversion of `e` to `System.IAsyncDisposable` shall not cause boxing to occur. | ||
| - Otherwise, the `finally` clause is expanded to an empty block: |
There was a problem hiding this comment.
If E is not a sealed type, should we generate the following, matching foreach-statement?
System.IAsyncDisposable d = e as System.IAsyncDisposable;
if (d != null) await d.DisposeAsync();
``` #ResolvedThere was a problem hiding this comment.
I don't think so. I don't remember why we'd decided that, but the code has:
// For async foreach, we don't do the runtime check
if ((!enumeratorType.IsSealed && !isAsync) ||
this.Conversions.ClassifyImplicitConversionFromType(enumeratorType,
isAsync ? this.Compilation.GetWellKnownType(WellKnownType.System_IAsyncDisposable) : this.Compilation.GetSpecialType(SpecialType.System_IDisposable),
ref useSiteInfo).IsImplicit)
{
builder.NeedsDisposal = true;
}
Relates to dotnet/roslyn#60022