【问题标题】:When should you use IEnumerable and GetEnumerator?什么时候应该使用 IEnumerable 和 GetEnumerator?
【发布时间】:2012-03-24 05:18:36
【问题描述】:

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

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

例如

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

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

是否有首选方式,还是由开发人员决定?

【问题讨论】:

标签: c# .net


【解决方案1】:

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

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; }
    }
}

无论如何,选择正确的设计始终取决于开发人员。

【讨论】:

  • 感谢 Balazs Tihanyi,我可以问一个关于您的示例的愚蠢问题吗,为什么您从 IEnumerable 而不是 IEnumberble 实现?我不确定。
  • 您为什么要这样做? IEnumerable&lt;Person&gt; 是通用且类型安全的。 IEnumerable 用于 .NET 1.1 或匿名类型。如果只实现IEnumerable 接口,则必须将列表项转换为它们的类型。
【解决方案2】:

我会这样做:

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

这样更简洁,您的用户不会在不应该的地方获得列表(他们可以将其转换为 List&lt;T&gt;毕竟),并且您不需要创建 List&lt;T&gt;object。

编辑:误解了这个问题。我认为如果这个类是一个集合,它应该实现IEnumerable&lt;T&gt;

【讨论】:

  • 我相信这里没有问这个问题,所以它可以是评论而不是答案,但无论如何从重构的角度来看是有意义的
【解决方案3】:

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

如果m_states 是引用类型,这仍然会创建一个列表,调用者可以再次操作添加/删除/更新元素(它是一个引用!) 不影响原始数据。

IEnumerable&lt;T&gt; 呢,它只是一种使返回类型泛型的方法,而不是与List&lt;T&gt; 类型强耦合。

【讨论】:

  • m_states 是一个引用类型。其声明为私有 List m_states = new List();我认为由于返回 IEnumerable 而不是 List 而无法操作方法返回?
  • @bobbo: 确定可以,如果你从返回的集合中取出一个元素并改变它的属性,你就改变了 original 元素的属性, 因为这是一个 reference 类型。
  • 好的,这是有道理的。但是,您的句子“如果 m_states 是引用类型,这仍然会创建一个新列表,调用者可以再次操作添加/删除/没有更新元素(这是一个引用!)而不影响原始数据。”令人困惑。您的意思是返回的新列表可以添加,元素可以删除但不能更新?我认为因为它返回 ienumerable 您可以修改列表中的元素,即像您说的那样更改属性,但您不能在列表中添加和删除项目。对吗?
  • 我的意思是:如果你想对该列表执行一些统计,从其中删除元素添加新的聚合值(比如说),它不会以 任何 方式影响 m_states 列表.
【解决方案4】:

我认为,如果您新实现的类与列表的行为方式相同,则无需实现它。如果您需要某种自定义逻辑,则取决于您要做什么;您可以继承列表,也可以实现 IEnumerable。这仅取决于要实现的目标。

【讨论】:

    【解决方案5】:

    您可能想检查一下: http://www.codeproject.com/Articles/4074/Using-IEnumerator-and-IEnumerable-in-the-NET-Frame

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

    【讨论】:

      【解决方案6】:

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

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2013-02-01
        • 2015-12-05
        • 2021-08-25
        • 2023-04-02
        • 2011-04-15
        • 2017-04-10
        • 2012-03-19
        • 2018-05-12
        相关资源
        最近更新 更多