Программирование C#, Java, Net - фото

Цикл foreach в C# (часть 2)


Оцените данную статью

Доброе время суток. Пришло время для продолжения рассказа о цикле foreach
в языке программирования C#. Из первой статьи вы уже немного знаете как пользоваться данным циклом, чем он отличается от привычного for. Так же были предложены примеры кода для обхода элементов коллекции List (System.Collections.Generic) и элементов массива. Но не был дан ответ, к каким же объектам можно
применять цикл foreach, а к каким нет.

Итак, цикл foreach можно применять только к объектам, реализующим интерфейс IEnumerable (пространство имен — System.Collections) или IEnumerable<T>> (пространство имен — System.Collections.Generic), в зависимости от коллекции объектов. Не путайте два эти интерфейса, первый надо реализовывать, когда у вас в качестве контейнера элементов допустим массив, второй — допустим, когда у вас контейнер List. Почему именно эти интерфейсы и зачем они нужны? Дело в том, что цикл foreach — это всего лишь достаточно удобная оболочка, которая внутри себя вызывает определенные свойства и методы самого объекта. Эти методы, свойства и необходимо реализовать, если мы хотим, чтобы объект можно было использовать в цикле foreach.
Чтобы стало понятнее, давайте рассмотрим пример:

    1. using System.Collections;
    2. public class TestCollection : IEnumerable
    3. {
    4.         private int[] array;
    5.         public TestCollection(int[] argList)
    6.         {
    7.             array = argList;
    8.         }
    9.         public IEnumerator GetEnumerator()
    10.         {
    11.             return new TestEnumerator(this);
    12.        }
    13.         private class TestEnumerator : IEnumerator
    14.         {
    15.             int position = 1;
    16.             TestCollection collection;
    17.         }
    18.         public TestEnumerator(TestCollection col)
    19.             {
    20.                 collection = col;
    21.             }
    22.         public bool MoveNext()
    23.             {
    24.                 if (position < collection.array.Length 1)
    25.                 {
    26.                     position++;
    27.                     return true;
    28.                 }
    29.                else
    30.                 {
    31.                     return false;
    32.                 }
    33.             }
    34.             public void Reset()
    35.             {
    36.                 position = 1;
    37.             }
    38.             object IEnumerator.Current
    39.             {
    40.                 get { return collection.array[position]; }
    41.             }
    42.         }
    43. }


Как видно из кода класс TestCollection реализует интерфейс IEnumerator,
для этого переопределяем метод GetEnumerator(). Данный метод возвращает объект (реализующий IEnumerator),
знающий как правильно обходить коллекцию. Класс TestEnumerator реализует IEnumerator,
в котором есть метод Reset() — он сбрасывает счетчик в начальную позицию, метод MoveNext() — он
сдвигает счетчик, и возвращает true — если еще мы не вышли за пределы коллекции, т.е. двигаться
к следующему элементу можно, и возвращает false — в противном случае.
Так же есть свойство Current — оно возвращает текущий элемент коллекции.

Отсюда не сложно догадаться как работает на цикл foreach изнутри. В начале вызывается
метод Reset(), затем после каждой итерации вызывается MoveNext() и свойство нужно
непосредственно в самом цикле для доступа к текущему элементу. Когда MoveNext() возвращает — false,
то мы выходим из цикла foreach.

Далее небольшой пример кода по использованию нашего класса TestCollection в цикле foreach:

    1. using System.Collections;
    2. int sum = 0;
    3. int []ar = {1, 2, 5, 3};
    4. TestCollection col = new TestCollection(ar);
    5. foreach(int value in col)
    6. {
    7.        sum += value;
    8. }


В общем как вы уже успели заметили цикл foreach не так и прост изнутри, как может показаться
на первый взгляд. И за данную легкость использования приходится заплатить производительностью. Но это не должно
вас пугать и для большинства задач foreach подходит отлично. И есть еще один ньюанс, про который лучше не забывать и стоит
обратить внимание при использовании цикла foreach…Не стоит изменять коллекцию элементов
внутри цикла, так как это может нарушить цикл.

На этом пожалуй всё о цикле foreach, если дойдут руки возможно будет и третья часть по данной теме.

Добавить комментарий

Ваш e-mail не будет опубликован. Обязательные поля помечены *