扩展 GetEnumerator
支持 foreach
循环。Extension GetEnumerator
support for foreach
loops.
总结Summary
允许 foreach 循环识别扩展方法 GetEnumerator 方法,该方法以其他方式满足 foreach 模式,并在该表达式被视为错误时循环使用。Allow foreach loops to recognize an extension method GetEnumerator method that otherwise satisfies the foreach pattern, and loop over the expression when it would otherwise be an error.
动机Motivation
这会在实现 c # 中的其他功能(包括异步和基于模式的析构)的情况下引入 foreach 内联。This will bring foreach inline with how other features in C# are implemented, including async and pattern-based deconstruction.
详细设计Detailed design
Spec 更改相对简单。The spec change is relatively straightforward. 修改 The foreach statement
此文本部分:We modify The foreach statement
section to this text:
Foreach 语句的编译时处理首先确定表达式的 集合类型 _、 _枚举器类型*_ 和 _ *元素类型**。The compile-time processing of a foreach statement first determines the collection type _, _enumerator type_ and _ element type of the expression. 这种决定将按如下方式进行:This determination proceeds as follows:
如果表达式的
X
类型是数组类型,则从到接口 (存在隐式引用转换,X
IEnumerable
因为System.Array
) 实现此接口。If the typeX
of expression is an array type then there is an implicit reference conversion fromX
to theIEnumerable
interface (sinceSystem.Array
implements this interface). 集合类型 _ 是IEnumerable
接口, _枚举器类型_ 为IEnumerator
接口,_ 元素类型 是数组类型的元素类型X
。The collection type _ is theIEnumerable
interface, the _enumerator type_ is theIEnumerator
interface and the _ element type is the element type of the array typeX
.如果表达式的
X
类型为,则dynamic
从 expression 到 Interface 的隐式转换IEnumerable
(隐式动态转换) 。If the typeX
of expression isdynamic
then there is an implicit conversion from expression to theIEnumerable
interface (Implicit dynamic conversions). 集合类型 _ 是IEnumerable
接口,而 _枚举器类型*_ 是IEnumerator
接口。The collection type _ is theIEnumerable
interface and the _enumerator type*_ is theIEnumerator
interface. 如果将var
标识符作为 _local_variable_type * 提供,则 元素类型 为dynamic
,否则为object
。If thevar
identifier is given as the _local_variable_type* then the element type isdynamic
, otherwise it isobject
.否则,请确定该类型是否
X
具有适当的GetEnumerator
方法:Otherwise, determine whether the typeX
has an appropriateGetEnumerator
method:
- 对
X
具有标识符GetEnumerator
且无类型参数的类型执行成员查找。Perform member lookup on the typeX
with identifierGetEnumerator
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. 如果成员查找产生了除方法组以外的任何内容,则建议发出警告。It is recommended that a warning be issued if member lookup produces anything except a method group or no match.- 使用生成的方法组和空参数列表执行重载决策。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. 如果重载决策产生了除明确的公共实例方法之外的任何内容,或者没有适用方法,则建议发出警告。It is recommended that a warning be issued if overload resolution produces anything except an unambiguous public instance method or no applicable methods.
- 如果该方法的返回类型
E
GetEnumerator
不是类、结构或接口类型,则会生成错误,并且不会执行任何其他步骤。If the return typeE
of theGetEnumerator
method is not a class, struct or interface type, an error is produced and no further steps are taken.- 成员查找是在上
E
用标识符Current
而不是类型参数执行的。Member lookup is performed onE
with the identifierCurrent
and no type arguments. 如果成员查找没有生成任何匹配项,则结果为错误,或结果为除允许读取的公共实例属性之外的任何内容,并不执行任何其他步骤。If the member lookup produces no match, the result is an error, or the result is anything except a public instance property that permits reading, an error is produced and no further steps are taken.- 成员查找是在上
E
用标识符MoveNext
而不是类型参数执行的。Member lookup is performed onE
with the identifierMoveNext
and no type arguments. 如果成员查找没有生成任何匹配项,则结果为错误,或结果为除方法组外的任何内容,并不执行任何其他步骤。If the member lookup produces no match, the result is an error, or the result is anything except a method group, an error is produced and no further steps are taken.- 使用空参数列表对方法组执行重载决策。Overload resolution is performed on the method group with an empty argument list. 如果重载决策导致没有适用的方法,导致不确定性,或者导致单个最佳方法,但该方法是静态的或非公共的,或者它的返回类型不是
bool
,则会生成错误,并且不会执行任何其他步骤。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, or its return type is notbool
, an error is produced and no further steps are taken.- 集合类型 _ 是
X
, _枚举器类型_ 为E
,_ 元素类型 是属性的类型Current
。The collection type _ isX
, the _enumerator type_ isE
, and the _ element type is the type of theCurrent
property.否则,请检查可枚举的接口:Otherwise, check for an enumerable interface:
- 如果
Ti
存在从到的隐式转换到的所有类型X
IEnumerable<Ti>
,则有一个唯一类型,这种类型不适用,T
T
dynamic
并且对于所有其他类型的Ti
隐式转换均IEnumerable<T>
为IEnumerable<Ti>
,则 集合类型 _ 是接口IEnumerable<T>
, _枚举器类型_ 是接口IEnumerator<T>
,而 _ 元素类型 是T
。If among all the typesTi
for which there is an implicit conversion fromX
toIEnumerable<Ti>
, there is a unique typeT
such thatT
is notdynamic
and for all the otherTi
there is an implicit conversion fromIEnumerable<T>
toIEnumerable<Ti>
, then the collection type _ is the interfaceIEnumerable<T>
, the _enumerator type_ is the interfaceIEnumerator<T>
, and the _ element type isT
.- 否则,如果有多个这样的类型
T
,则会生成错误,并且不会执行任何其他步骤。Otherwise, if there is more than one such typeT
, then an error is produced and no further steps are taken.- 否则,如果存在从到接口的隐式转换
X
System.Collections.IEnumerable
,则 集合类型 _ 是此接口, _枚举器类型_ 是接口System.Collections.IEnumerator
,而 _ 元素类型 是object
。Otherwise, if there is an implicit conversion fromX
to theSystem.Collections.IEnumerable
interface, then the collection type _ is this interface, the _enumerator type_ is the interfaceSystem.Collections.IEnumerator
, and the _ element type isobject
.否则,确定类型 "X" 是否具有适当的
GetEnumerator
扩展方法:Otherwise, determine whether the type 'X' has an appropriateGetEnumerator
extension method:
- 对标识符为的类型执行扩展方法查找
X
GetEnumerator
。Perform extension method lookup on the typeX
with identifierGetEnumerator
. 如果成员查找不会生成匹配项,或者它产生了多义性,或者产生了不是方法组的匹配项,则会生成错误,并且不会执行任何其他步骤。If the member lookup does not produce a match, or it produces an ambiguity, or produces a match which is not a method group, an error is produced and no further steps are taken. 如果成员查找产生了除方法组外的任何内容,或者没有匹配项,则建议发出警告。It is recommended that a warning be issues if member lookup produces anything except a method group or no match.- 使用生成的方法组和一个类型的参数来执行重载决策
X
。Perform overload resolution using the resulting method group and a single argument of typeX
. 如果重载决策不生成适用的方法、导致歧义,或者导致单个最佳方法,但该方法不可访问,则不会执行任何其他步骤。If overload resolution produces no applicable methods, results in an ambiguity, or results in a single best method but that method is not accessible, an error is produced an no further steps are taken.
- 如果是一个结构类型,则此解决方法允许 ref 传递第一个参数
X
,而 ref 类型为in
。This resolution permits the first argument to be passed by ref ifX
is a struct type, and the ref kind isin
.- 如果该方法的返回类型
E
GetEnumerator
不是类、结构或接口类型,则会生成错误,并且不会执行任何其他步骤。If the return typeE
of theGetEnumerator
method is not a class, struct or interface type, an error is produced and no further steps are taken.- 成员查找是在上
E
用标识符Current
而不是类型参数执行的。Member lookup is performed onE
with the identifierCurrent
and no type arguments. 如果成员查找没有生成任何匹配项,则结果为错误,或结果为除允许读取的公共实例属性之外的任何内容,并不执行任何其他步骤。If the member lookup produces no match, the result is an error, or the result is anything except a public instance property that permits reading, an error is produced and no further steps are taken.- 成员查找是在上
E
用标识符MoveNext
而不是类型参数执行的。Member lookup is performed onE
with the identifierMoveNext
and no type arguments. 如果成员查找没有生成任何匹配项,则结果为错误,或结果为除方法组外的任何内容,并不执行任何其他步骤。If the member lookup produces no match, the result is an error, or the result is anything except a method group, an error is produced and no further steps are taken.- 使用空参数列表对方法组执行重载决策。Overload resolution is performed on the method group with an empty argument list. 如果重载决策导致没有适用的方法,导致不确定性,或者导致单个最佳方法,但该方法是静态的或非公共的,或者它的返回类型不是
bool
,则会生成错误,并且不会执行任何其他步骤。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, or its return type is notbool
, an error is produced and no further steps are taken.- 集合类型 _ 是
X
, _枚举器类型_ 为E
,_ 元素类型 是属性的类型Current
。The collection type _ isX
, the _enumerator type_ isE
, and the _ element type is the type of theCurrent
property.否则,将生成错误,并且不执行任何其他步骤。Otherwise, an error is produced and no further steps are taken.
对于 await foreach
,规则的修改方式也类似。For await foreach
, the rules are similarly modified. 该规范所需的唯一更改是 Extension methods do not contribute.
从说明中删除该行,因为该规范的其余部分基于以上规则,这些规则的名称替换为模式方法的不同名称。The only change that is required to that spec is removing the Extension methods do not contribute.
line from the description, as the rest of that spec is based on the above rules with different names substituted for the pattern methods.
缺点Drawbacks
每次更改都会增加语言的复杂性,并且这可能会使设计不是 ed 的东西 foreach
foreach
(如) Range
。Every change adds additional complexity to the language, and this potentially allows things that weren't designed to be foreach
ed to be foreach
ed, like Range
.
备选方法Alternatives
不执行任何操作。Doing nothing.
未解决的问题Unresolved questions
目前无。None at this point.