溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊(cè)×
其他方式登錄
點(diǎn)擊 登錄注冊(cè) 即表示同意《億速云用戶服務(wù)條款》

C#中foreach的實(shí)現(xiàn)原理是什么

發(fā)布時(shí)間:2021-07-07 18:03:41 來(lái)源:億速云 閱讀:152 作者:Leah 欄目:編程語(yǔ)言

這篇文章將為大家詳細(xì)講解有關(guān)C#中foreach的實(shí)現(xiàn)原理是什么,文章內(nèi)容質(zhì)量較高,因此小編分享給大家做個(gè)參考,希望大家閱讀完這篇文章后對(duì)相關(guān)知識(shí)有一定的了解。

對(duì)集合中的要素進(jìn)行遍歷是所有編碼中經(jīng)常涉及到的操作,因此大部分編程語(yǔ)言都把此過(guò)程寫(xiě)進(jìn)了語(yǔ)法中,比如C#中的foreach。經(jīng)常會(huì)看到下面的遍歷代碼:

var lstStr = new List<string> { "a", "b" };
   foreach (var str in lstStr)
      {
        Console.WriteLine(str);
      }

實(shí)際此代碼的執(zhí)行過(guò)程:

var lstStr = new List<string> {"a", "b"};
   IEnumerator<string> enumeratorLst = lstStr.GetEnumerator();
   while (enumeratorLst.MoveNext())
      {
        Console.WriteLine(enumeratorLst.Current);
      }

會(huì)發(fā)現(xiàn)有GetEnumerator()方法和IEnumerator<string>類(lèi)型,這就涉及到可枚舉類(lèi)型和枚舉器的概念。

為了方便理解,以下為非泛型示例:

// 摘要:
//   公開(kāi)枚舉器,該枚舉器支持在非泛型集合上進(jìn)行簡(jiǎn)單迭代。
  public interface IEnumerable
  {
    // 摘要:
    //   返回一個(gè)循環(huán)訪問(wèn)集合的枚舉器。
    //
    // 返回結(jié)果:
    //   可用于循環(huán)訪問(wèn)集合的 System.Collections.IEnumerator 對(duì)象。
    IEnumerator GetEnumerator();
  }

實(shí)現(xiàn)了此接口的類(lèi)稱(chēng)為可枚舉類(lèi)型,是可以用foreach進(jìn)行遍歷的標(biāo)志。

方法GetEnumerator()的返回值是枚舉器,可以理解為游標(biāo)。

// 摘要:
//   支持對(duì)非泛型集合的簡(jiǎn)單迭代。
  public interface IEnumerator
  {
    // 摘要:
    //   獲取集合中的當(dāng)前元素。
    //
    // 返回結(jié)果:
    //   集合中的當(dāng)前元素。
    //
    // 異常:
    //  System.InvalidOperationException:
    //   枚舉數(shù)定位在該集合的第一個(gè)元素之前或最后一個(gè)元素之后。
    object Current { get; }

    // 摘要:
    //   將枚舉數(shù)推進(jìn)到集合的下一個(gè)元素。
    //
    // 返回結(jié)果:
    //   如果枚舉數(shù)成功地推進(jìn)到下一個(gè)元素,則為 true;如果枚舉數(shù)越過(guò)集合的結(jié)尾,則為 false。
    //
    // 異常:
    //  System.InvalidOperationException:
    //   在創(chuàng)建了枚舉數(shù)后集合被修改了。
    bool MoveNext();
    //
    // 摘要:
    //   將枚舉數(shù)設(shè)置為其初始位置,該位置位于集合中第一個(gè)元素之前。
    //
    // 異常:
    //  System.InvalidOperationException:
    //   在創(chuàng)建了枚舉數(shù)后集合被修改了。
    void Reset();
  }

以下是自定義一個(gè)迭代器的示例(https://msdn.microsoft.com/en-us/library/system.collections.ienumerator.aspx):

using System;
using System.Collections;

// Simple business object.
public class Person
{
  public Person(string fName, string lName)
  {
    this.firstName = fName;
    this.lastName = lName;
  }

  public string firstName;
  public string lastName;
}

// Collection of Person objects. This class
// implements IEnumerable so that it can be used
// with ForEach syntax.
public class People : IEnumerable
{
  private Person[] _people;
  public People(Person[] pArray)
  {
    _people = new Person[pArray.Length];

    for (int i = 0; i < pArray.Length; i++)
    {
      _people[i] = pArray[i];
    }
  }

// Implementation for the GetEnumerator method.
  IEnumerator IEnumerable.GetEnumerator()
  {
    return (IEnumerator) GetEnumerator();
  }

  public PeopleEnum GetEnumerator()
  {
    return new PeopleEnum(_people);
  }
}

// When you implement IEnumerable, you must also implement IEnumerator.
public class PeopleEnum : IEnumerator
{
  public Person[] _people;

  // Enumerators are positioned before the first element
  // until the first MoveNext() call.
  int position = -1;

  public PeopleEnum(Person[] list)
  {
    _people = list;
  }

  public bool MoveNext()
  {
    position++;
    return (position < _people.Length);
  }

  public void Reset()
  {
    position = -1;
  }

  object IEnumerator.Current
  {
    get
    {
      return Current;
    }
  }

  public Person Current
  {
    get
    {
      try
      {
        return _people[position];
      }
      catch (IndexOutOfRangeException)
      {
        throw new InvalidOperationException();
      }
    }
  }
}

class App
{
  static void Main()
  {
    Person[] peopleArray = new Person[3]
    {
      new Person("John", "Smith"),
      new Person("Jim", "Johnson"),
      new Person("Sue", "Rabon"),
    };

    People peopleList = new People(peopleArray);
    foreach (Person p in peopleList)
      Console.WriteLine(p.firstName + " " + p.lastName);

  }
}

/* This code produces output similar to the following:
 *
 * John Smith
 * Jim Johnson
 * Sue Rabon
 *
 */

在有了yield這個(gè)關(guān)鍵字以后,我們可以通過(guò)這樣的方式來(lái)創(chuàng)建枚舉器:

using System;
using System.Collections;

// Simple business object.
public class Person
{
  public Person(string fName, string lName)
  {
    this.firstName = fName;
    this.lastName = lName;
  }

  public string firstName;
  public string lastName;
}

// Collection of Person objects. This class
// implements IEnumerable so that it can be used
// with ForEach syntax.
public class People : IEnumerable
{
  private Person[] _people;

  public People(Person[] pArray)
  {
    _people = new Person[pArray.Length];

    for (int i = 0; i < pArray.Length; i++)
    {
      _people[i] = pArray[i];
    }
  }

  // Implementation for the GetEnumerator method.
  IEnumerator IEnumerable.GetEnumerator()
  {
    for (int i = 0; i < _people.Length; i++)
    {
      yield return _people[i];
    }
  }

}


class App
{
  static void Main()
  {
    Person[] peopleArray = new Person[3]
    {
      new Person("John", "Smith"),
      new Person("Jim", "Johnson"),
      new Person("Sue", "Rabon"),
    };

    People peopleList = new People(peopleArray);
    foreach (Person p in peopleList)
      Console.WriteLine(p.firstName + " " + p.lastName);
  }
}

關(guān)于C#中foreach的實(shí)現(xiàn)原理是什么就分享到這里了,希望以上內(nèi)容可以對(duì)大家有一定的幫助,可以學(xué)到更多知識(shí)。如果覺(jué)得文章不錯(cuò),可以把它分享出去讓更多的人看到。

向AI問(wèn)一下細(xì)節(jié)

免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點(diǎn)不代表本網(wǎng)站立場(chǎng),如果涉及侵權(quán)請(qǐng)聯(lián)系站長(zhǎng)郵箱:is@yisu.com進(jìn)行舉報(bào),并提供相關(guān)證據(jù),一經(jīng)查實(shí),將立刻刪除涉嫌侵權(quán)內(nèi)容。

AI