title | description | ms.date |
---|---|---|
Collections |
Learn about collections in C#, which are used to work with groups of objects. Collections have different characteristics regarding adding and removing elements, modifying elements, and enumerating the collection elements. |
08/22/2023 |
The .NET runtime provides many collection types that store and manage groups of related objects. Some of the collection types, such as xref:System.Array?displayProperty=nameWithType, xref:System.Span%601?displayProperty=nameWithType, and xref:System.Memory%601?displayProperty=nameWithType are recognized in the C# language. In addition, interfaces like xref:System.Collections.Generic.IEnumerable%601?displayProperty=nameWithType are recognized in the language for enumerating the elements of a collection.
Collections provide a flexible way to work with groups of objects. You can classify different collections by these characteristics:
- Element access: Every collection can be enumerated to access each element in order. Some collections access elements by index, the element's position in an ordered collection. The most common example is xref:System.Collections.Generic.List%601?displayProperty=nameWithType. Other collections access elements by key, where a value is associated with a single key. The most common example is xref:System.Collections.Generic.Dictionary%602?displayProperty=nameWithType. You choose between these collection types based on how your app accesses elements.
- Performance profile: Every collection has different performance profiles for actions like adding an element, finding an element, or removing an element. You can pick a collection type based on the operations used most in your app.
- Grow and shrink dynamically: Most collections supporting adding or removing elements dynamically. Notably, xref:System.Array, xref:System.Span%601?displayProperty=nameWithType, and xref:System.Memory%601?displayProperty=nameWithType don't.
In addition to those characteristics, the runtime provides specialized collections that prevent adding or removing elements or modifying the elements of the collection. Other specialized collections provide safety for concurrent access in multi-threaded apps.
You can find all the collection types in the .NET API reference. For more information, see Commonly Used Collection Types and Selecting a Collection Class.
Note
For the examples in this article, you might need to add using directives for the System.Collections.Generic
and System.Linq
namespaces.
Arrays are represented by xref:System.Array?displayProperty=fullName and have syntax support in the C# language. This syntax provides more concise declarations for array variables.
xref:System.Span%601?displayProperty=nameWithType is a ref struct
type that provides a snapshot over a sequence of elements without copying those elements. The compiler enforces safety rules to ensure the Span
can't be accessed after the sequence it references is no longer in scope. It's used in many .NET APIs to improve performance. xref:System.Memory%601 provides similar behavior when you can't use a ref struct
type.
Beginning with C# 12, all of the collection types can be initialized using a Collection expression.
An indexable collection is one where you can access each element using its index. Its index is the number of elements before it in the sequence. Therefore, the element reference by index 0
is the first element, index 1
is the second, and so on. These examples use the xref:System.Collections.Generic.List%601 class. It's the most common indexable collection.
The following example creates and initializes a list of strings, removes an element, and adds an element to the end of the list. After each modification, it iterates through the strings by using a foreach statement or a for
loop:
:::code language="csharp" source="./snippets/shared/Collections.cs" id="SnippetCreateList":::
The following example removes elements from a list by index. Instead of a foreach
statement, it uses a for
statement that iterates in descending order. The xref:System.Collections.Generic.List%601.RemoveAt%2A method causes elements after a removed element to have a lower index value.
:::code language="csharp" source="./snippets/shared/Collections.cs" id="SnippetRemoveItemByIndex":::
For the type of elements in the xref:System.Collections.Generic.List%601, you can also define your own class. In the following example, the Galaxy
class that is used by the xref:System.Collections.Generic.List%601 is defined in the code.
:::code language="csharp" source="./snippets/shared/Collections.cs" id="SnippetCustomList":::
These examples use the xref:System.Collections.Generic.Dictionary%602 class. It's the most common dictionary collection. A dictionary collection enables you to access elements in the collection by using the key of each element. Each addition to the dictionary consists of a value and its associated key.
The following example creates a Dictionary
collection and iterates through the dictionary by using a foreach
statement.
:::code language="csharp" source="./snippets/shared/Collections.cs" id="SnippetDictionary":::
The following example uses the xref:System.Collections.Generic.Dictionary%602.ContainsKey%2A method and the xref:System.Collections.Generic.Dictionary%602.Item%2A property of Dictionary
to quickly find an item by key. The Item
property enables you to access an item in the elements
collection by using the elements[symbol]
in C#.
:::code language="csharp" source="./snippets/shared/Collections.cs" id="SnippetFindInDictionary":::
The following example instead uses the xref:System.Collections.Generic.Dictionary%602.TryGetValue%2A method to quickly find an item by key.
:::code language="csharp" source="./snippets/shared/Collections.cs" id="SnippetFindInDictionary2":::
An iterator is used to perform a custom iteration over a collection. An iterator can be a method or a get
accessor. An iterator uses a yield return statement to return each element of the collection one at a time.
You call an iterator by using a foreach statement. Each iteration of the foreach
loop calls the iterator. When a yield return
statement is reached in the iterator, an expression is returned, and the current location in code is retained. Execution is restarted from that location the next time that the iterator is called.
For more information, see Iterators (C#).
The following example uses an iterator method. The iterator method has a yield return
statement that is inside a for
loop. In the ListEvenNumbers
method, each iteration of the foreach
statement body creates a call to the iterator method, which proceeds to the next yield return
statement.
:::code language="csharp" source="./snippets/shared/Collections.cs" id="SnippetIteratorMethod":::
Language-integrated query (LINQ) can be used to access collections. LINQ queries provide filtering, ordering, and grouping capabilities. For more information, see Getting Started with LINQ in C#.
The following example runs a LINQ query against a generic List
. The LINQ query returns a different collection that contains the results.
:::code language="csharp" source="./snippets/shared/Collections.cs" id="ShowLINQ":::