Do not use collections from System.Collections unless you are maintaining legacy code. They don’t provide type safety and they have poor performance when used with value types.
The collections can be easily grouped in a few categories based on the interfaces they implement. These determine which operations are supported by a collection and consequently in which scenarios can they be used.
The common interface for collections is the ICollection interface. It inherits from the IEnumerable interface which provides the means for iterating through a collection of items. The ICollection interface adds the Count property and methods for modifying the collection:
The authors of the Base Class Library (BCL) believed that these suffice for implementing a simple collection. Three different interfaces extend this base interface in different ways to provide additional functionalities.
- Lists
- The IList interface describes collections with items which can be accessed by their index
- Sets
- ISet interface describes a set, i.e. a collection of unique items which doesn’t guarantee to preserve their order. it will only add the item to the collection if it’s not already present in it. The return value will indicate if the item was added. The most basic implementation of ISet is the HashSet class. If you want the items in the set to be sorted, you can use SortedSet instead.
- Dictionaries
- IDictionary<tkey, tvalue= » »> stores key-value pairs instead of standalone values. The indexer allows getting and setting the values based on a key instead of an index:</tkey,></tkey,>.
Queue and Stack
The Queue class implements a FIFO (First in, First out) collection. Only a single item in it is directly accessible, i.e. the one that’s in it for the longest time.
The Stack class is similar to Queue, but it implements a LIFO (Last in, First out) collection. The single item that’s directly accessible in this collection is the one that was added the most recently.
Thread safety
The regular generic classes in the Base Class Library have one very important deficiency they are not entirely thread-safe. While most of them support several concurrent readers, the reading operations are still not thread-safe as no concurrent write access is allowed. As soon as the collection has to be modified, any access to it from multiple threads must be synchronized.The simplest approach to implementing such synchronization involves using the lock statement with a common synchronization object but the Base Class Library comes with the ReaderWriterLockSlim class which can be used to implement this specific functionality simpler.
Concurrent collections
The concurrent collections in the System.Collections.Concurrent namespace provide thread-safe implementations of collection interfaces.
Immutable collections
Immutable collections aren’t included in the Base Class Library. To use them, the System.Collections.Immutable NuGet package must be installed in the project. They take a different approach to making collections thread-safe. Instead of using synchronization locks as concurrent collections do, immutable collections can’t be changed after they are created. This automatically makes them safe to use in multi-threaded scenarios since there’s no way for another thread to modify them and make the state inconsistent.
When choosing a collection to use in your code, always start by thinking through which operations you will need to perform on that collection. Based on that, you can select the most appropriate collection interface. Unless you have any other special requirements, go with an implementation from the System. Collections.Generic namespace. If you’re writing a multithreaded application and will need to modify the collection from multiple threads, choose the concurrent implementation of the same interface instead. Consider immutable collections if their behavior and performance match your requirements best.