Как использовать ключевое слово foreach для пользовательских объектов в С#

Может ли кто-нибудь поделиться простым примером использования ключевого слова foreach с пользовательскими объектами?

Ответы

Ответ 1

Учитывая теги, я предполагаю, что вы имеете в виду в .NET - и я буду говорить о С#, как о том, что знаю.

В заявлении foreach (обычно) используются IEnumerable и IEnumerator или их общие кузены. Утверждение формы:

foreach (Foo element in source)
{
    // Body
}

где source реализует IEnumerable<Foo> примерно эквивалентно:

using (IEnumerator<Foo> iterator = source.GetEnumerator())
{
    Foo element;
    while (iterator.MoveNext())
    {
        element = iterator.Current;
        // Body
    }
}

Обратите внимание, что IEnumerator<Foo> располагается в конце, однако утверждение завершается. Это важно для блоков итератора.

Чтобы реализовать IEnumerable<T> или IEnumerator<T> самостоятельно, самый простой способ - использовать блок итератора. Вместо того, чтобы писать здесь все подробности, лучше всего просто отнести вас к главе 6 С# в глубине, которая является бесплатной загрузкой. Вся глава 6 посвящена итераторам. У меня есть еще несколько статей на моем сайте С# на глубине:

В качестве быстрого примера:

public IEnumerable<int> EvenNumbers0To10()
{
    for (int i=0; i <= 10; i += 2)
    {
        yield return i;
    }
}

// Later
foreach (int x in EvenNumbers0To10())
{
    Console.WriteLine(x); // 0, 2, 4, 6, 8, 10
}

Чтобы реализовать IEnumerable<T> для типа, вы можете сделать что-то вроде:

public class Foo implements IEnumerable<string>
{
    public IEnumerator<string> GetEnumerator()
    {
        yield return "x";
        yield return "y";
    }

    // Explicit interface implementation for nongeneric interface
    IEnumerator IEnumerable.GetEnumerator()
    {
        return GetEnumerator(); // Just return the generic version
    }
}

Ответ 2

(я предполагаю, что здесь С#)

Если у вас есть список настраиваемых объектов, вы можете просто использовать foreach так же, как и с любым другим объектом:

List<MyObject> myObjects = // something
foreach(MyObject myObject in myObjects)
{
     // Do something nifty here
}

Если вы хотите создать свой собственный контейнер, вы можете использовать ключевое слово yield (от .Net 2.0 и выше, я считаю) вместе с интерфейсом IEnumerable.

class MyContainer : IEnumerable<int>
{
    private int max = 0;
    public MyContainer(int max)
    {
        this.max = max;
    }

    public IEnumerator<int> GetEnumerator()
    {
        for(int i = 0; i < max; ++i)
            yield return i;
    }

    IEnumerator IEnumerable.GetEnumerator()
    {
        return GetEnumerator();
    }
}

И затем используйте его с foreach:

MyContainer myContainer = new MyContainer(10);
foreach(int i in myContainer)
    Console.WriteLine(i);