【问题标题】:What is the need for custom collections and enumerables?自定义集合和枚举需要什么?
【发布时间】:2009-10-21 13:27:43
【问题描述】:

为什么我们需要通过实现IEnumerableIEnumerator 来自定义集合和自定义枚举(我知道IEnumerableIEnumerator 做了什么以及如何实现它们)。问题是任何事情都可以用字典、哈希表、列表等集合来完成。那么为什么我们要使用自定义枚举来将不可枚举的项变成可枚举的集合呢?

几乎大部分 ASP.NET 对象都是可枚举的,如string[]int[],那我为什么要依赖自己的逻辑进行枚举呢?

【问题讨论】:

  • 我不确定问题是什么。您是否在询问可能实现自定义 IEnumerable 功能而不是使用内置数组/列表/字典/等类型的原因?

标签: c# asp.net collections


【解决方案1】:

这些接口最有趣的地方在于,您可以拥有具有该类型属性的类:

public class Customer
{
    public IEnumerable<Order> orders { get; set; }
}

(或IList&lt;Order&gt;)。 这比使用 List 有趣得多,如果你想改变它的类型并且很多其他代码都使用这个属性,这可能会成为一个问题。

【讨论】:

    【解决方案2】:

    这个问题有两个相关但不相同的部分。首先要回答第二部分,现在我们已经有了 yield 语法,以及内置集合类选项的过多(我喜欢这个词!)可以派生,您应该很少需要自己实现 IEnumerator 或 IEnumerable 了。因此,在绝大多数情况下,自定义集合类不应该实现 IEnumerable 和 IEnumerator 本身,它应该派生自已经为您执行此操作的现有内置集合类之一。

    其次,回答第一个问题,为什么要构建这样一个自定义集合类?为了将您希望在客户端代码的多个位置重用的逻辑/功能封装在一个地方,而不必在任何地方重复它。假设您需要代表发票的集合。 List&lt;Invoice&gt; 会这样做,但是如果您只需要一个模块中两个或三个地方的过期发票,而另一个模块中只需要指定状态的发票,并且只需要一个特定的计费模块中的客户发票,假设您需要在代码中的多个位置通过发票编号查找并提取特定发票。好吧,如果您拥有的只是List&lt;Invoice&gt;,那么执行我所描述的所有功能都必须在您想要执行这些功能的客户端代码中的每个地方重复......如果您将此功能封装在自定义集合类中,您只需编写一次,并将其维护在一个唯一的地方,并通过实例上的集合类方法从任何地方访问它...

       public Invoices: List<Invoice>
       {
            public Invoices OverDueInvoices 
            { get {return this.Where( i => i.IsOverdue()); } }
    
            public Invoices InvoicesByState(string stateAbbrev)
            { return this.Where( i => i.State == stateAbbrev);  }
    
            public Invoice this[int invoiceId]
            { get { return this.Find( i => i.InvoiceId == invoiceId); } }
    
            // extra functionality as required 
       }
    

    【讨论】:

    • 没错。还值得指出的是,您有时确实需要 .NET 不提供的自定义功能,例如双向字典、排序包或多字典等。
    【解决方案3】:

    如果您要枚举的对象不是来自简单的内存集合,您可能会实现 IEnumerator,但您希望能够抽象出实际创建对象的代码并像使用它们一样使用它们一个简单的数组。

    例如,您可以创建一个实现IEnumerator&lt;string&gt;FileEnumerator 类,并在每次调用MoveNext 时读取文件的下一行。然后,您可以像读取字符串数组一样读取文件,而无需将整个文件存储在内存中。

    【讨论】:

      【解决方案4】:

      泛型是相当强大的,所以我已经很长时间没有需要编写一个全新的类来实现 IEnumerable 和 IEnumerator 了。对于我的集合中需要一些自定义功能的情况,我可以从 List 或 Dictionary 继承,而不是自己实现这些接口。

      【讨论】:

        【解决方案5】:

        我很难再找到编写客户枚举的理由了。有很多方法可以根据需要动态生成 IEnumerable 集合。除了 LINQ 按需生成新集合的能力之外,还有一些在非泛型集合上实现的方法,例如 AsEnumerable()、OfType 和 Cast,它们将从非泛型集合构建泛型枚举。

        正如 Peter 所指出的,接口使类之间的耦合更加灵活,但这并不需要编写自定义类。 List 实现了 IEnumerable,因此将 List 分配给他的“orders”属性就可以满足接口的需求。

        如果不时需要自定义功能,也可以将它们编写为扩展方法。这是扩展类的一种非常方便的方法,无需定义和实现全新的类。

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 2010-12-08
          • 2017-08-25
          • 2017-04-02
          • 2011-06-29
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多