通过


使 Visual C# 类在 foreach 语句中可用

本文演示如何使用 IEnumerable 接口和 IEnumerator 接口创建可在语句中使用的 foreach 类。

原始产品版本: Visual Studio
原始 KB 数: 322022

IEnumerator 接口

IEnumerable 并且 IEnumerator 经常一起使用。 尽管这些接口相似(并且具有类似的名称),但它们具有不同的用途。

IEnumerator 接口为类内部的集合提供迭代功能。 IEnumerator 要求实现三种方法:

  • 该方法 MoveNext 将集合索引递增 1,并返回一个布尔值,该值指示是否已到达集合的末尾。

  • 该方法 Reset 将集合索引重置为 -1 的初始值。 这会使枚举器失效。

  • 该方法 Current 返回当前对象的位置 position

    public bool MoveNext()
    {
        position++;
        return (position < carlist.Length);
    }
    public void Reset()
    {
        position = -1;
    }
    public object Current
    {
        get { return carlist[position];}
    }
    

IEnumerable 接口

IEnumerable 接口提供对 foreach 迭代的支持。 IEnumerable 要求实现 GetEnumerator 该方法。

public IEnumerator GetEnumerator()
{
    return (IEnumerator)this;
}

何时使用哪个接口

最初,你可能会发现使用这些接口会令人困惑。 该 IEnumerator 接口提供对类中的集合类型对象的迭代。 该 IEnumerable 接口允许使用 foreach 循环进行枚举。 但是, GetEnumerator 接口的方法 IEnumerable 返回接口 IEnumerator 。 因此,若要实现 IEnumerable,还必须实现 IEnumerator。 如果未实现IEnumerator,则无法将返回值从GetEnumerator接口的方法IEnumerableIEnumerator强制转换为接口。

总之,使用 IEnumerable 类实现 IEnumerator的要求。 如果要为这两个接口提供支持 foreach,请实现这两个接口。

分步示例

以下示例演示如何使用这些接口。 在此示例中,在名为 <a0/a0IEnumerator> 的类中使用和IEnumerable接口。 该 cars 类具有对象的内部数组 car 。 由于这两个 foreach 接口的实现,客户端应用程序可以使用构造来枚举此内部数组。

  1. 按照以下步骤在 Visual C# 中创建新的控制台应用程序项目:

    1. 开始Microsoft Visual Studio .NET 或 Visual Studio。
    2. “文件” 菜单上,指向 “新建” ,然后单击 “项目”
    3. 单击“项目类型”下的“Visual C# 项目”,然后单击“模板下的“控制台应用程序”。
    4. “名称 ”框中,键入 ConsoleEnum
  2. 将Class1.cs重命名host.cs,然后将host.cs中的代码替换为以下代码:

    using System;
    namespace ConsoleEnum
    {
       class host
       {
           [STAThread]
           static void Main(string[] args)
           {
               cars C = new cars();
               Console.WriteLine("\nInternal Collection (Unsorted - IEnumerable,Enumerator)\n");
               foreach(car c in C)
               Console.WriteLine(c.Make + "\t\t" + c.Year);
               Console.ReadLine();
           }
       }
    }
    
  3. “项目”菜单上,单击“添加类,然后在“名称”框中键入汽车

  4. 将car.cs中的代码替换为以下代码:

    using System;
    using System.Collections;
    namespace ConsoleEnum
    {
       public class car
       {
           private int year;
           private string make;
           public car(string Make,int Year)
           {
               make=Make;
               year=Year;
           }
           public int Year
           {
               get  {return year;}
               set {year=value;}
           }
           public string Make
           {
               get {return make;}
               set {make=value;}
           }
       }//end class
    }//end namespace
    
  5. “项目”菜单上,单击“添加类”以向项目添加其他类,然后在名称”框中键入汽车

  6. 将cars.cs中的代码替换为以下代码:

    using System;
    using System.Collections;
    namespace ConsoleEnum
    {
        public class cars : IEnumerator,IEnumerable
        {
           private car[] carlist;
           int position = -1;
           //Create internal array in constructor.
           public cars()
           {
               carlist= new car[6]
               {
                   new car("Ford",1992),
                   new car("Fiat",1988),
                   new car("Buick",1932),
                   new car("Ford",1932),
                   new car("Dodge",1999),
                   new car("Honda",1977)
               };
           }
           //IEnumerator and IEnumerable require these methods.
           public IEnumerator GetEnumerator()
           {
               return (IEnumerator)this;
           }
           //IEnumerator
           public bool MoveNext()
           {
               position++;
               return (position < carlist.Length);
           }
           //IEnumerable
           public void Reset()
           {
               position = -1;
           }
           //IEnumerable
           public object Current
           {
               get { return carlist[position];}
           }
        }
      }
    
  7. 运行该项目。

以下输出显示在 控制台 窗口中:

Ford            1992
Fiat            1988
Buick           1932
Ford            1932
Dodge           1999
Honda           1977

最佳做法

本文中的示例尽可能简单,以更好地解释这些接口的使用。 若要使代码更加可靠并确保代码使用当前的最佳做法准则,请按如下所示修改代码:

  • 在嵌套类中实现 IEnumerator ,以便可以创建多个枚举器。
  • Current 此方法 IEnumerator提供异常处理。 如果集合的内容发生更改,将 reset 调用该方法。 因此,当前枚举器失效,并且你会收到异常 IndexOutOfRangeException 。 其他情况也可能导致此异常。 因此,实现一个 Try...Catch 块来捕获此异常并引发 InvalidOperationException 异常。
using System;
using System.Collections;
namespace ConsoleEnum
{
    public class cars : IEnumerable
    {
        private car[] carlist;
  
        //Create internal array in constructor.
        public cars()
        {
            carlist= new car[6]
            {
                new car("Ford",1992),
                new car("Fiat",1988),
                new car("Buick",1932),
                new car("Ford",1932),
                new car("Dodge",1999),
                new car("Honda",1977)
            };
        }
        //private enumerator class
        private class  MyEnumerator:IEnumerator
        {
            public car[] carlist;
            int position = -1;

            //constructor
            public MyEnumerator(car[] list)
            {
                carlist=list;
            }
            private IEnumerator getEnumerator()
            {
                return (IEnumerator)this;
            }
            //IEnumerator
            public bool MoveNext()
            {
                position++;
                return (position < carlist.Length);
            }
            //IEnumerator
            public void Reset()
            {
                position = -1;
            }
            //IEnumerator
            public object Current
            {
                get
                {
                    try
                    {
                        return carlist[position];
                    }
                    catch (IndexOutOfRangeException)
                    {
                        throw new InvalidOperationException();
                    }
                }
            }
        }  //end nested class
      public IEnumerator GetEnumerator()
      {
          return new MyEnumerator(carlist);
      }
    }
}