25

有人可以分享一个将foreach关键字与自定义对象一起使用的简单示例吗?

4

3 回答 3

47

鉴于标签,我假设您的意思是 .NET - 我将选择谈论 C#,因为这就是我所知道的。

foreach语句(通常)使用IEnumerableandIEnumerator或它们的通用表亲。表格声明:

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

其中sourceimplementsIEnumerable<Foo>大致相当于

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

请注意,IEnumerator<Foo>在末尾设置了,但是该语句退出了。这对于迭代器块很重要。

要自己实现IEnumerable<T>IEnumerator<T>最简单的方法是使用迭代器块。与其在这里写下所有的细节,不如直接参考C# in Depth 的第 6 章,这是免费下载的。第 6 章的全部内容都是关于迭代器的。我的 C# in Depth 站点上还有几篇文章:

作为一个简单的例子:

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 : 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
    }
}
于 2008-12-08T09:17:23.747 回答
9

(我在这里假设 C#)

如果您有一个自定义对象列表,您可以像使用任何其他对象一样使用 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);
于 2008-12-08T09:20:18.887 回答
1

来自MSDN 参考

foreach 语句不限于IEnumerable类型,可以应用于满足以下条件的任何类型的实例:

具有GetEnumerator返回类型为类、结构或接口类型的公共无参数方法,该方法的返回类型GetEnumerator具有公共 Current 属性和MoveNext返回类型为布尔值的公共无参数方法。

如果您声明这些方法,则可以使用foreach关键字而无需IEnumerable开销。为了验证这一点,截取这段代码,看看它不会产生编译时错误:

class Item
{
    public Item Current { get; set; }
    public bool MoveNext()
    {
        return false;
    }
}

class Foreachable
{
    Item[] items;
    int index;
    public Item GetEnumerator()
    {
        return items[index];
    }
}

Foreachable foreachable = new Foreachable();
foreach (Item item in foreachable)
{

}
于 2020-04-11T11:55:25.897 回答