C# foreach如何调用GetEnumerator()?通过IEnumerable引用还是通过。。。?

C# foreach如何调用GetEnumerator()?通过IEnumerable引用还是通过。。。?,c#,C#,变量e对或不可见 表达式x或 嵌入语句或任何其他源 程序代码 在listary的情况下,返回的枚举数保存在变量e中(即它的值保存在变量e中)(因此变量e是一个可变结构)。但是根据上面的摘录,e不可访问我的源代码,那么我如何传递这个结构呢(除非我编写的代码手动执行foreach语句自动执行的操作) (二) 在标识符为当前且无类型参数的E上执行成员查找。如果 成员查找不产生匹配,结果为错误,或结果为任何内容 除了允许读取的公共实例属性外,将生成一个错误,并且 已采取进一步措施 如果我们在类(X)本身

变量e对或不可见 表达式x或 嵌入语句或任何其他源 程序代码

listary
的情况下,返回的枚举数保存在变量
e
中(即它的值保存在变量
e
中)(因此变量
e
是一个可变结构)。但是根据上面的摘录,
e
不可访问我的源代码,那么我如何传递这个结构呢(除非我编写的代码手动执行
foreach
语句自动执行的操作)

(二)

在标识符为当前且无类型参数的E上执行成员查找。如果 成员查找不产生匹配,结果为错误,或结果为任何内容 除了允许读取的公共实例属性外,将生成一个错误,并且 已采取进一步措施

如果我们在类(
X
)本身中实现
GetEnumerator
,那么
Current
也应该在类(
E
)本身中实现(因此
E
不应该显式实现
Current
),既然编译器不会费心去检查
IEnumerator/IEnumerator
接口,如果成员查找(在
E
上,标识符为
当前的
)不能产生匹配

(三)

如果只有一个类型T,则存在从X到 接口System.Collections.Generic.IEnumerable,则集合类型为 接口,枚举器类型为接口 System.Collections.Generic.IEnumerator,元素类型为T

根据以上内容,如果
foreach
必须检查
IEnumerable
接口,那么
foreach
将始终使用
IEnumerator
版本的
Current
?因此,如果
E
显式地实现
IEnumerator
当前版本的
Current
,并且如果它还在类本身中实现另一个版本的
Current
,那么
foreach
将始终调用
IEnumerable
当前版本的

(四)

GetEnumerator方法被记录为返回以下方法之一:

你所说的其中一个(复数)是什么意思?您提供的链接显示
GetEnumerator
(由
List
实现)仅返回
struct
类型

(五)

g。集合类型为X,枚举数类型为E,元素类型为当前属性的类型


也许这是一个无用的问题—根据上面的说明,
foreach
不会检查某些用户定义集合实际存储的元素类型,而是假设元素类型与
Current
属性返回的类型相同

foreach的行为在语言规范第8.8.4节中有详细说明。简而言之

foreach(T在表达式中)

  • 如果表达式是数组*,请使用IEnumerable接口(*请参阅下面的Eric Lippert评论。)
  • 否则,若表达式具有GetEnumerator方法,则使用该方法
  • 否则,如果表达式可转换为
    IEnumerable
    ,请使用该接口和
    IEnumerator
    (以及相关方法)
  • 否则,如果表达式可转换为
    IEnumerable
    ,请使用该接口和
    IEnumerator
    (以及相关方法)
还有各种各样的错误情况和我正在掩饰的东西。但是,简而言之,如果您的集合是泛型的,那么它将使用泛型接口选项

来自C#3.0语言规范(第8.8.4节):

foreach语句的编译时处理首先确定表达式的集合类型、枚举数类型和元素类型。该决定如下所述:

  • 如果表达式的类型X是数组类型,则存在从X到System.Collections.IEnumerable接口的隐式引用转换(因为System.array实现了此接口)。集合类型是System.Collections.IEnumerable接口,枚举器类型是System.Collections.IEnumerable接口,元素类型是数组类型X的元素类型
  • 否则,确定类型X是否具有适当的GetEnumerator方法:

    a。使用标识符GetEnumerator和无类型参数对类型X执行成员查找。如果成员查找未产生匹配,或产生歧义,或产生非方法组的匹配,请检查可枚举接口,如下所述。如果成员查找生成除方法组以外的任何内容或不匹配,建议发出警告

    b。使用生成的方法组和空参数列表执行重载解析。如果重载解析导致没有适用的方法,导致歧义,或导致单个最佳方法,但该方法是静态的或非公共的,请检查可枚举接口,如下所述。如果重载解析产生除明确的公共实例方法或无适用方法之外的任何结果,建议发出警告

    c。如果GetEnumerator方法的返回类型E不是类、结构或接口类型,则会产生错误,并且不会采取进一步的步骤

    d。在标识符为当前且无类型参数的E上执行成员查找。如果成员查找未生成匹配项,则结果为错误,或者结果为除允许读取的公共实例属性之外的任何内容,则会生成错误,并且不会采取进一步的步骤

    e。成员查找在标识符为MoveNext且无类型参数的E上执行。如果成员查找未生成匹配项,则结果为错误,或者结果为除方法组以外的任何内容,则会生成错误,并且不会进一步存储
        static void Main(string[] args)
        {
            List<int> listArray = new List<int>();
            listArray.Add(100);
            foreach (int item in listArray)
                Console.WriteLine(item);
        }
    
    {
       E e = ((C)(x)).GetEnumerator();
       try {
          V v;
          while (e.MoveNext()) {
             v = (V)(T)e.Current;
             embedded-statement
          }
       }
       finally {
          … // Dispose e
       }
    }
    
    var iterator = listArray.GetEnumerator();
    while(iterator.MoveNext())
    {
       var item = iterator.Current;
       Console.WriteLine(item);
    }
    
    foreach(int x in myObjects)
    
    foreach(string x in myInts)