What is the need for custom collections and enumerables?
Why do we need custom collection and custom enumeration by implementing IEnumerable
and IEnumerator
(I know what IEnumerable
and IEnumerator
does and how to implement them). The question is as anything can be done with collections like Dictionary, Hashtable, List. So why do we use custom enumeration to make non-enumerable items to enumerable collections?开发者_开发技巧
Almost most of the ASP.NET object are enumerable like string[]
, int[]
, then why should I depend on my own logic for enumeration?
The most interesting thing about those interfaces are that you can have classes that have properties of that type:
public class Customer
{
public IEnumerable<Order> orders { get; set; }
}
(or an IList<Order>
).
This is much more interesting than using List which could become a problem if you want to change its type and a lot of other code uses this property.
The question has two parts that are related but not the same.. To answer second part first, now that we have the yield syntax, and the plethora (I love that word!) of built-in collection class options that you can derive from, you should very very rarely have to implement IEnumerator or IEnumerable yourself anymore. So, in the great majority of cases, a custom collection class should not implement IEnumerable and IEnumerator itself, it should derive from one of the existing built-in collection classes that already do that for you.
Secondly, to answer the first question, Why build such a custom collection class? in order to encapsulate logic/functionality that you wish to reuse in multiple places in client code, in a single place instead of having to repeat it everywhere. Say you have a need to represent collections of Invoices. List<Invoice>
will do it, but if you need only the overdue Invoices in two or three places in one module, and only the invoices for a specified state in another module, and only a specific customer's invoices in the billing module, and let's say you need to find and extract a specific invoice by it's Invoice Number in several places in code. Well if all you have is List<Invoice>
all the functionality to do what I described would have to be repeated in every place in client code where you wanted to perform those functions... If you encapsulate this functionality in a custom collection class, you only write it once, and maintain it in one and only place, and access it from anywhere through the collection class methods on the instance...
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
}
You might implement IEnumerator if the objects you're enumerating aren't coming from a simple in-memory collection, but you want to be able to abstract away the code that actually creates the objects and consume them just as though they were a simple array.
For example, you could create a FileEnumerator
class that implements IEnumerator<string>
and reads the next line of a file each time MoveNext
is called. You could then read through the file as though it were an array of strings, without having to store the whole file in memory.
Generics are quite powerful, so I haven't had the need to write a brand new class that implements IEnumerable and IEnumerator in a long time. For the cases where I need some custom functionality in my collections, I've been able to inherit from List or Dictionary instead of implementing those interfaces myself.
I'd be hard pressed to come up with a reason to write a customer enumeration any more. There are so many ways to generate IEnumerable collections on the fly, as needed. Besides LINQ's capability to generate new collections on demand, there are also methods implemented on non-generic collectgions, such as AsEnumerable(), OfType, and Cast that will build generic enumerations from non-generic collections.
As Peter points out, interfaces make for more flexible coupling between classes, but that doesn't require writing custom classes. A List implements IEnumerable, so assigning a List to his "orders" property meets the needs of the interface.
If custom capabilities are needed from time to time, they can also be written as extension methods. That's a very handy way to extend a class without having to define and implement whole new classes.
精彩评论