何时应该使用IEnumerable和GetEnumerator

本文关键字:GetEnumerator IEnumerable 何时应 | 更新日期: 2023-09-27 18:28:59

在我们的许多项目中,我看到了一些自定义集合/或容器类,它们包含某种泛型集合,例如List(of T)类。

它们通常有一个GetXXX方法,该方法返回自定义集合类使用的任何类型的IEnumerable,因此可以使用foreach循环对内部集合进行迭代。

例如

public IEnumerable<UploadState> GetStates
{
    get
    {
        return new List<UploadState>(m_states);
    }
}

我的问题是,这些类是否应该实现IEnumerable接口,并在List本身上调用GetEnumerator

有没有首选的方式,或者由开发人员决定?

何时应该使用IEnumerable和GetEnumerator

如果您的类是一个自定义集合类,那么是的,它应该实现IEnumerable<T>。在这种情况下,内部列表的公共属性将是多余的。想象一个简单的类:

public class People : IEnumerable<Person>
{
    List<Person> persons = new List<Person>();
    public IEnumerator<Person> GetEnumerator()
    {
        return persons.GetEnumerator();
    }
}

但是,如果您的类不能像集合一样工作,那么为其元素提供一个公共IEnumerable属性:

public class Flight
{
    List<Person> passengers = new List<Person>();
    public IEnumerable<Person> Passengers
    {
        get { return passengers; }
    }
}

不管怎样,总是由开发人员来选择正确的设计。

我会这样做:

public IEnumerable<UploadState> GetStates
{
    get
    {
        foreach (var state in m_states) { 
            yield return state; 
        }
    }
}

它更干净,用户不会在不应该得到的地方得到列表(毕竟他们可以将其转换为List<T>),并且您不需要创建List<T>对象。

编辑:误解了这个问题。我认为如果这个类是一个集合,那么它应该实现IEnumerable<T>

请考虑在您的代码示例中创建了一个新的列表。我不知道什么是m_states,但如果这是一个值类型集合,则可以创建原始列表的克隆。通过这种方式,可以从调用方Add/Remove/Update元素中操作返回列表而不影响原始数据。

如果m_states是引用类型,这仍然会创建一个列表,该列表可以由调用方Add/Remove/No更新元素(它是引用!)再次操作,而不会影响原始数据。

IEnumerable<T>呢,它只是使返回类型成为泛型的一种方式,而不是与List<T>类型强耦合。

我认为,如果你新实现的类的行为与列表相同,那么就没有必要实现它。如果你需要某种自定义逻辑,这取决于你想做什么;您可以继承列表,也可以实现IEnumerable。这只是取决于要实现的目标。

您可能需要检查以下内容:http://www.codeproject.com/Articles/4074/Using-IEnumerator-and-IEnumerable-in-the-NET-Frame

我还没有完全阅读,但我认为这回答了你的问题。

您应该基于System.Collections.ObjectModel命名空间中的一个类来派生自定义集合类。它们已经包含IEnumerable<T>和非通用IEnumerable接口的实现。