Back to Blog
C#

C# List to Array: Converting Collections with ToArray()

c# list to array: Convert a List<T> to an array in C# with ToArray(), CopyTo(), and understand the type, performance, and memory implications of each approach.

C#.NETList<T>ArraysCollections
Diagram showing a C# List<T> being converted to an array with ToArray(), illustrating the element copy process.

c# list to array requires a clear understanding of the core syntax, runtime behavior, and practical implementation patterns demonstrated in the examples below.

When you need to convert a C# list to an array, List<T> provides the ToArray() method for exactly this purpose. The choice between ToArray(), CopyTo(), and manual conversion depends on what you need the resulting array for and how the data will be used.

The Core Conversion: ToArray()

List<string> names = new List<string> { "Ada", "Grace", "Linus" }; string[] namesArray = names.ToArray();

ToArray() creates a new array whose length equals the list's Count, copies every element in order, and returns it. The original list remains unchanged. This is the simplest and most common way to convert a List<T> to an array, and it works for any type parameter.

The method is an instance method on List<T>, so no additional using directives or extensions are required. It is also available through IEnumerable<T> as a LINQ extension method, but the instance version is identical in behavior for a List<T>.

What ToArray() Does Internally

The method allocates a fresh array of size Count and performs a shallow element copy. For value types, each value is copied directly. For reference types, the array receives references to the same objects, so the list and the array share object instances. Mutating an object through the array is visible through the list, and vice versa.

The list is not modified, and the array is completely independent in terms of length and resizing behavior. Removing elements from the list after conversion has no effect on the array, and resizing the array is not possible because arrays are fixed-size.

Type Compatibility Between List<T> and T[]

The element type is preserved exactly. A List<int> becomes an int[], a List<Customer> becomes a Customer[], and a List<IDisposable> becomes an IDisposable[]. The conversion never widens or narrows the element type.

If you need a different element type, you must transform the elements first:

List<object> items = new List<object> { 1, "two", 3.0 }; string[] strings = items.OfType<string>().ToArray();

OfType<T>() filters and casts, producing only the elements that match the target type. If you need to convert every element and want an exception on mismatch, Cast<T>() throws InvalidCastException on the first non-matching element. Neither approach changes the underlying data; they only produce a new collection of the requested type.

CopyTo() for Reusing an Existing Array

When an array already exists, CopyTo() copies list elements into it without allocating a new array:

List<int> values = new List<int> { 10, 20, 30 }; int[] destination = new int[5]; values.CopyTo(destination, 1);

The elements land in destination starting at index 1. The destination must have enough space from the start index to accommodate Count elements; otherwise, ArgumentException is thrown. This pattern is useful when the array is a preallocated buffer, such as in serialization or interop code, where repeated allocations would be wasteful.

CopyTo() has overloads that accept a destination array only, or a destination array with a starting index. There is also a CopyTo(int, T[], int, int) overload that copies a range of elements from the list, which is useful when only part of the list needs to be transferred.

Performance and Memory Behavior

ToArray() runs in O(n) time with a single allocation proportional to the list's count. The original list stays alive until it is no longer referenced, so converting a large list and keeping both references doubles the memory footprint temporarily.

If conversion happens repeatedly in a hot path, consider whether the consumer actually needs an array. Passing IReadOnlyList<T> or IEnumerable<T> avoids the copy entirely when the consumer only reads sequentially. When an array is genuinely required, CopyTo() into a reused buffer avoids per-call allocations if the list size is stable.

For value-type lists, the copy is a direct memory copy of the elements, which is efficient. For reference-type lists, only the references are copied, so the cost is proportional to the number of elements, not the size of the referenced objects.

Choosing Between Array and List

Arrays are fixed-size and give the lowest indexed-access overhead. Lists provide dynamic resizing and mutation methods. The decision is about the data's lifetime and the consumer's requirements:

  • Use an array when the count is fixed and known in advance, or when an external API demands T[].
  • Use a List<T> when elements are added or removed after construction.
  • Convert to an array only at the boundary where the array is required, rather than converting back and forth.

A common mistake is converting a list to an array for iteration. foreach works identically on both, and List<T> provides the same indexed access as an array. If the consumer only iterates, the conversion is unnecessary overhead.

Common Mistakes and Edge Cases

An empty list converts to an empty array, not null. A list containing null references produces an array with null entries; ToArray() does not filter or validate.

List<T>.Capacity does not affect the result. ToArray() uses Count, so a list created with a large capacity but few elements yields a small array. If you rely on Capacity to predict the array size, the result will surprise you.

Concurrent modification is the riskiest edge case. List<T> is not thread-safe, so calling ToArray() while another thread adds or removes elements can throw or produce inconsistent data. Synchronize access with a lock, or copy the list into a snapshot before converting. The thread-safe collections in System.Collections.Concurrent do not include a list type, so synchronization is your responsibility when using List<T> in a concurrent context.

c# list to array: Practical Usage and Code Examples | RYUSLOG DEV