Table of Contents
- Chapter 7. Collections
- 7.1 Enumeration
- 7.1.1 IEnumerable and IEnumerator
- 7.1.2 IEnumerable<T> and IEnumerator<T>
- 7.1.3 Implementing the Enumeration Interfaces
- 7.2 The ICollection and IList Interfaces
- 7.2.1 ICollection<T> and ICollection
- 7.2.2 IList<T> and IList
- 7.2.3 IReadOnlyCollection<T> and IReadOnlyList<T>
- 7.3 The Array Class
- 7.4 List, Queues, Stacks and Sets
- 7.5 Dictionaries
- 7.6 Customizable Collections and Proxies
- 7.7 Immutable Collections
- 7.8 Plugging in Equality and Order
Chapter 7. Collections
.NET provides multiple standard types to store and manage collections of objects. e.g. resiable list, link lists, sorted and unsorted dictionaries, array
- Only array is part of C# language, while others are classes
- these types can be categorized in 3:
- Interfaces that define standard collection protocols
- Ready-to-use collection classes (e.g. lists)
- Base classes for buiding app-specific collections
7.1 Enumeration
All collections regardless complexity (e.g. simple array, or linked list, to complex hashtables) requires the ability to traverse the contents of the collection.
- .NET BCL support this feature through interfaces
IEnumeable
andIEnumerator
- This interface expose a common traversal API
Picture: set of collection interfaces
7.1.1 IEnumerable and IEnumerator
IEnumerator
IEnumerator
interface defines the basic low-level protocol:
- collection elements are traversed/enumerated in forward only manner
Declaration of IEnumerator
interface:
public interface IEnumerator
{
bool MoveNext(); // Advances the current element "cursor" to next position
object Current { get; } // returns element at current position
void Reset();
}
Reset()
mainly used for Component Object Mdoel (COM) interperability; It's not universally supported
IEnumerable
- Enumerator are usually not directly implmented by collections.
- More often, collections provide enumerator (i.e.
IEnumerator
) by implementing interfaceIEnumerable
Declaration of IEnumerable
public interface IEnumerable
// Act as IEnumerator Provider
{
IEnumerator GetEnumerator(); // Single method return an enumerator
}
Benefit of GetEnumerator()
:
IEnumerable
provides flexibility that iteration logic can be transferred to another class- Several consumers can enumerate the collection at once without interfering with another.
e.g. use IEnumerable
& IEnumerator
:
string s = "Hello"; // string implement IEnumerable interface
// Because string implements IEnumerable, we can call GetEnumerator();
IEnumerator rator = s.GetEnumerator();
while (rator.MoveNext())
{
char c = (char) rator.Current;
Console.Write(c + "."); // Output H.e.l.l.o
}
C# provide foreach
as syntax shortcut for using IEnumerable interface (i.e. declare IEnumerator first then .MoveNext()
)
e.g. syntax shortcut
string s = "Hello";
foreach (char c in s)
{
Console.Write(c + ".");
}
7.1.2 IEnumerable<T>
and IEnumerator<T>
Extended generic versions of IEnumerable<T>
and IEnumeratlr<T>
provides benefits:
- strong static type safety
- avoid overhead of boxing
- More convenient to consumer
Note:
- Array implement
IEnumerable<T>
automatically foreach
works onIEnumerable<T>
pretty well
e.g. declare of generic IEnumerable<T>
and IEnuemrator<T>
public interface IEnumerator<T> : IEnumerator, IDisposable
{
T Current { get; }
}
public interface IEnumerable<T> : IEnumerable
{
IEnumerator<T> GetEnumerator();
}
e.g. effect of type safety
void Test(IEnumerable<int> number) {...}
Test("Hello"); // Compile-time error
IEnumerable<T>
and IDisposable
IEnumerable<T>
inherits from both interface of IEnumerable
and IDisposable
, provide benefit:
- Enumerator hold references to resources such as database connections
- Ensure that resources are released when enumeration is complete
foreach
as syntax shortcut recorgnize it and perform follow transform
foreach (var element in somethingEnuemrable) {...}
// Translate to
using (var rator = somethingEnumerable.GetEnumerator())
// ensure disposal
{
while (rator.MoveNext())
{
var element = rator.Current;
...
}
}
TODO: Details are in book, not summarized