There are two main types of collections: non-generic (ICollection) and generic
(ICollection<T>).
Non-generic collections only exist because .NET did not originally have generic data types. They shouldn’t be used because:
- They are untyped at compile time. The frequent casting from
objectand the actual type is error-prone; it’s easy to put the wrong type in the wrong collection. - Value types need to be boxed as
object, e.g.,List<int>stores its data in anint[], which is more performant than usingobject[]as that requires boxing.
Non-Generic Collections (ICollection)
ICollection extends IEnumerable.
Properties of ICollection
Count gets the number of elements contained in the ICollection.
IsSynchronized is true if access to the ICollection is thread-safe.
SyncRoot is an object that can be used to synchronize the ICollection.
Methods of ICollection
CopyTo copies the elements of the collection to an Array starting at a
particular Array index.
GetEnumerator is an enumerator that iterates through a collection.
Extension Methods of ICollection
Cast<TResult> casts the elements of an IEnumerable to TResult.
OfType<TResult> filters the TResult instances in an IEnumerable.
AsParallel enables parallelization of a query.
AsQueryable converts an IEnumerable into an IQueryable.
Generic Collections (ICollection<T>)
ICollection<T> extends IEnumerable<T>.
Properties of ICollection<T>
Compared to ICollection, keeps Count, but lacks IsSynchronized and
SyncRoot.
IsReadOnlye is true if the ICollection<T> is read-only.
Methods of ICollection<T>
Compared to ICollection, keeps CopyTo and GetEnumerator.
Add, Clear, Contains, and Remove.
Extension Methods of ICollection<T>
Compared to ICollection, keeps Cast, OfType, AsParallel, and
AsQueryable.
Conversion to Other Collection Types
ToFrozen* for Dictionary and Set create immutable, read-only collections
that are optimized for fast lookup and enumeration.
To* and ToImmutable* for Array, Dictionary, HashSet, List,
SortedDictionary, and SortedSet. Additionally, ToLookup creates a
collection of keys mapped to one or more values .
Filtering Elements in a Sequence
All and Any test elements in the sequence against a predicate.
Where filters a sequence of values based on a predicate.
Distinct and DistinctBy produce distinct elements from a sequence.
Fetching and Adding Scalars
Single returns the only element that satisfies the predicate and throws if
more than one such element exists. SingleOrDefault is like Single but
returns a default value if no such element exists.
Prepend and Append add a value to the beginning and end of a sequence,
respectively.
First, FirstOrDefault, Last, LastOrDefault, ElementAt and
ElementAtOrDefault for index-based selection.
Operating on Multiple Sequences
Concat concatenates two sequences.
Set operations between two sequences: Except and ExceptBy for the
difference; Intersect and IntersectBy for the intersection; Union and
UnionBy for the union.
Join and GroupJoin correlates elements of two sequences by a specified key.
SequenceEqual tests whether two sequences are equal.
Projecting Elements to a Different Type
Select projects each element into a new form. SelectMany flattens the
resulting sequences into one sequence.
AsEnumerable changes the compile-time type of source from a type that
implements IEnumerable<T> to IEnumerable<T> itself. Sample use-case:
foregoing a custom implementation of Where().
Reducing a Sequence
Aggregate and AggregateBy apply an accumulator function, akin to reduce in
other languages. There are mathematical aggregations such as Average, Max,
MaxBy, Min, MinBy, and Sum.
Count and CountBy count the number of elements that satisfy a predicate.
LongCount is similar but returns an Int64. TryGetNonEnumeratedCount
attempts to get the count without forcing an enumeration.
Iterating Through a Sequence
Chunk splits the elements of a sequence into chunks of size at most size.
DefaultIfEmpty returns the sequence if non-empty and otherwise returns a
singleton collection with the defined default value.
GroupBy groups the elements of a sequence by a specified key.
Index returns an enumerable that incorporates the element’s index into a
tuple.
Order, OrderDescending, OrderBy, and OrderByDescending sort the elements
of a sequence.
Reverse inverts the order of elements in a sequence.
Skip and SkipLast bypass a specified number of elements in the sequence and
returns the remaining ones. SkipWhile checks a predicate instead of counting.
Take, TakeLast, and TakeWhile are inverses.
Zip produces a sequence of tuples with elements from two/three sequences, or
two sequences and a computed sequence.
References
- Collections and Data Structures - .NET | Microsoft Learn. learn.microsoft.com . Accessed Sep 6, 2025.
- platform-compat/docs/DE0006.md at master ยท dotnet/platform-compat. github.com . Accessed Sep 6, 2025.
- ICollection Interface (System.Collections) | Microsoft Learn. learn.microsoft.com . Accessed Sep 6, 2025.
- ICollection<T> Interface (System.Collections.Generic) | Microsoft Learn. learn.microsoft.com . Accessed Sep 6, 2025.
- System.Collections.Frozen Namespace | Microsoft Learn. learn.microsoft.com . Accessed Sep 6, 2025.
- Lookup<TKey,TElement> Class (System.Linq) | Microsoft Learn. learn.microsoft.com . Accessed Sep 6, 2025.
- Enumerable.AsEnumerable<TSource>(IEnumerable<TSource>) Method (System.Linq) | Microsoft Learn. learn.microsoft.com . Accessed Sep 6, 2025.
This is different from the capacity, which is the number of elements that a collection can contain. For most collections, when the current capacity is reached, the memory is reallocated, and the elements are copied from the old collection to the new one. To avoid poor performance from multiple reallocations, set the initial capacity to the estimated size of the collection.