为什么我们需要通过实施IEnumerable
和IEnumerator
来获取自定义集合和自定义枚举(我知道IEnumerable
和IEnumerator
做了什么以及如何实现它们)。问题是,可以使用Dictionary,Hashtable,List等集合完成任何操作。那么为什么我们使用自定义枚举来为可枚举的集合创建不可枚举的项目呢?
几乎大多数ASP.NET对象都是可枚举的,如string[]
,int[]
,那为什么我应该依靠自己的枚举逻辑呢?
答案 0 :(得分:2)
关于这些接口最有趣的事情是你可以拥有具有该类型属性的类:
public class Customer
{
public IEnumerable<Order> orders { get; set; }
}
(或IList<Order>
)。
这比使用List更有趣,如果你想改变它的类型并且许多其他代码使用这个属性,它可能会成为一个问题。
答案 1 :(得分:1)
如果您枚举的对象不是来自简单的内存中集合,您可能会实现IEnumerator,但是您希望能够抽象出实际创建对象并消耗它们的代码,就好像它们是一个简单的数组。
例如,您可以创建一个实现FileEnumerator
的{{1}}类,并在每次调用IEnumerator<string>
时读取文件的下一行。然后,您可以读取文件,就好像它是一个字符串数组,而不必将整个文件存储在内存中。
答案 2 :(得分:1)
问题有两个相关但不相同的部分。首先回答第二部分,现在我们有了yield语法,以及内置集合类选项的过多(我喜欢那个词!)可以派生出来,你应该很少自己实现IEnumerator或IEnumerable。因此,在绝大多数情况下,自定义集合类不应该实现IEnumerable和IEnumerator本身,它应该来自已经为您执行此操作的现有内置集合类之一。
其次,回答第一个问题,为什么要构建这样的自定义集合类?为了将您希望在客户端代码中的多个位置重用的逻辑/功能封装在一个地方,而不是在任何地方重复它。假设您需要代表发票集合。 List<Invoice>
会这样做,但如果您只需要一个模块中两个或三个位置的逾期发票,而只需要另一个模块中指定状态的发票,而且只需要一个特定的<在计费模块中发送客户的发票,假设您需要在代码中的几个位置通过发票编号查找并提取特定发票。好吧,如果您拥有的只是List<Invoice>
,那么我所描述的所有功能都必须在您想要执行这些功能的客户端代码中的每个地方重复...如果您将此功能封装在自定义集合类中,你只需编写一次,并将其保存在一个地方,并通过实例上的集合类方法从任何地方访问它......
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
}
答案 3 :(得分:0)
泛型非常强大,所以我没有必要编写一个在很长一段时间内实现IEnumerable和IEnumerator的全新类。对于我需要在我的集合中使用某些自定义功能的情况,我已经能够从List或Dictionary继承而不是自己实现这些接口。
答案 4 :(得分:0)
我很难想出一个写客户枚举的理由。根据需要,有很多方法可以动态生成IEnumerable集合。除了LINQ按需生成新集合的能力之外,还有非泛型集合实现的方法,例如AsEnumerable(),OfType和Cast,它们将构建来自非泛型集合的通用枚举。
正如Peter所指出的,接口使类之间的耦合更加灵活,但这并不需要编写自定义类。 List实现了IEnumerable,因此将List分配给他的“orders”属性可以满足接口的需要。
如果需要不时使用自定义功能,也可以将它们编写为扩展方法。这是扩展类而不必定义和实现全新类的非常方便的方法。