如何在C#中将类定义为IEnumerable?

28

我有一个类和一个泛型List在里面,但是它是私有的。

class Contacts
{
    List<Contact> contacts;
    ...
}

我希望能让这个类的工作方式像这样:

foreach(Contact in contacts) .... ;

像这样(不起作用):

Contacts c;
foreach(Contact in c) .... ;

在上面的例子中,联系人类实例c必须逐项返回contacts(c的私有成员)中的每一项。

我该怎么做呢?我知道它必须是一个带有yield return的IEnumerable,但在哪里声明呢?

5个回答

40

实现 IEnumerable 接口:

class Contacts : IEnumerable<Contact>
{
    List<Contact> contacts;

    #region Implementation of IEnumerable
    public IEnumerator<Contact> GetEnumerator()
    {
        return contacts.GetEnumerator();
    }

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

1
它们之间有什么区别? - Ivan Prodanov
2
@John:这两种方法之间的区别是什么?一种是实现IEnumerable,另一种是IEnumerable<>。当你实现IEnumerable<>时,你也必须实现IEnumerable。 - LightStriker
但是在第二个方法“Contacts.IEnumerable.GetEnumerator()”中,我遇到了这个错误:包含类型没有实现接口“System.Collections.IEnumerable”。 - Ivan Prodanov
@John:在编译时?我直接将它复制粘贴到解决方案中,它可以编译并正常工作。 - LightStriker
哦,它继承了IENumerable...抱歉。 - Ivan Prodanov
1
确实无法编译。 - Virus721

16

@TimeSchmelter:那么foreach语句如何知道这个类实现了GetEnumerator方法,如果它没有接口来声明实现契约呢? - LightStriker
2
@Marc-AndréJutras:foreach查找GetEnumerator。在这里查看语言规范的详细信息:https://dev59.com/fuo6XIcBkEYKwwoYTy4d#3679993 - Tim Schmelter
有趣。一直以来都认为接口是必须的。知道这个真好。"省略IEnumerable和IEnumerator的缺点是,集合类不再与其他常见语言运行时兼容的语言的foreach语句或等效语句互操作。" ...哦...那太致命了。 - LightStriker
如果我们使用List,这个答案就足够了。 - Ronald Abellano

6
public class Contacts: IEnumerable
{
     ...... 
    public IEnumerator GetEnumerator()
    {
        return contacts.GetEnumerator();
    }
}

这应该对你有所帮助。

4
class Program
{
    static void Main(string[] args)
    {
        var list = new Contacts();
        var a = new Contact() { Name = "a" };
        var b = new Contact() { Name = "b" };
        var c = new Contact() { Name = "c" };
        var d = new Contact() { Name = "d" };
        list.ContactList = new List<Contact>();
        list.ContactList.Add(a);
        list.ContactList.Add(b);
        list.ContactList.Add(c);
        list.ContactList.Add(d);

        foreach (var i in list)
        {
            Console.WriteLine(i.Name);
        }
    }
}

class Contacts : IEnumerable<Contact>
{
    public List<Contact> ContactList { get; set; }

    public IEnumerator<Contact> GetEnumerator()
    {
        return ContactList.GetEnumerator();
    }

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

class Contact
{
    public string Name { get; set; }
}

4

你觉得只是扩展List<Contact>怎么样?

如果你不想扩展其他任何类,这是一个非常简单、快速的选项:

class Contacts :List<Contact>
{   
}

1
这可能不是对问题的直接回答,但我认为这个答案被严重低估了。在某些情况下,扩展List<Contact>可能是最好的解决方案! :-) - Björn Larsson
这是一个很好的方法。在某些情况下,蒂姆的答案可能更可取,因为它可以通过强制调用者仅与公开的方法进行交互来防止对列表的自由修改。 - Anil

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接