Back to Blog
C#

C# Array Copy: Methods, Performance, and Pitfalls

c# array copy: Learn how to copy arrays in C# using Array.Copy, Clone, LINQ, and manual loops. Understand shallow vs deep copy and when each method fits.

C#Array.CopyArray.CloneLINQ ToArrayDeep Copy
Two arrays side by side, with an arrow indicating a copy operation from one to the other, representing C# array copy methods.

When you assign one array variable to another in C#, you are not copying the elements—you are copying the reference to the same array object. This is a common source of bugs when the original array is modified later. To actually copy the contents, you need an explicit copy operation. This article covers the main ways to perform a c# array copy, explains the differences between shallow and deep copies, and gives practical guidance on choosing the right method.

Reference vs. Value Semantics in Array Assignment

Arrays in C# are reference types. The variable holds a reference to the array object on the managed heap, not the data itself. Consider this code:

int[] source = { 1, 2, 3 }; int[] target = source; target[0] = 99; Console.WriteLine(source[0]); // 99

Both source and target point to the same array instance. Modifying through either variable affects the same underlying data. This is not a copy. If you need an independent array, you must explicitly create a new array and populate it with the elements from the original.

The distinction becomes more important when the array contains reference types, such as strings or custom objects. Even if you copy the array itself, the copied array still holds references to the same objects. That is a shallow copy. A deep copy would also clone the objects themselves, which is often not what you want and can be expensive.

Using Array.Copy for Fast, Range-Controlled Copies

Array.Copy is a static method that copies a range of elements from one array to another. It is efficient because it performs a direct memory block copy for value types and a reference copy for reference types. The method has several overloads; the most common takes the source array, source index, destination array, destination index, and length.

int[] source = { 1, 2, 3, 4, 5 }; int[] target = new int[5]; Array.Copy(source, 0, target, 0, source.Length);

This copies all five elements. You can also copy a subset:

int[] partial = new int[2]; Array.Copy(source, 1, partial, 0, 2); // copies elements at indices 1 and 2

Array.Copy requires the destination array to be large enough to hold the copied elements. If not, it throws an ArgumentException. It also handles type conversion automatically if the source and destination are compatible, but for best performance, keep the same type.

One important detail: Array.Copy performs a shallow copy. If the array contains reference types, both arrays will reference the same objects. For value types like int, struct, or enum, the values themselves are copied, so the arrays are fully independent.

Using Clone() for a Quick Shallow Copy

Array.Clone() is an instance method that returns a shallow copy of the array. It creates a new array of the same length and copies each element. For value types, this is effectively a deep copy; for reference types, it is still shallow.

int[] source = { 1, 2, 3 }; int[] target = (int[])source.Clone();

Because Clone() returns object, you must cast it to the correct array type. The cast is safe as long as the source array's runtime type matches.

Clone() is convenient when you need a complete copy and don't need to control the destination array. It is slightly less flexible than Array.Copy because you cannot copy a subset or specify a destination index. However, for a simple full copy, it is concise and readable.

LINQ ToArray() and Other Convenience Methods

LINQ provides ToArray() as an extension method on IEnumerable<T>. You can use it to create a new array from an existing one:

int[] source = { 1, 2, 3 }; int[] target = source.ToArray();

ToArray() internally allocates a new array and copies the elements. It works on any sequence, not just arrays, which makes it useful when you have a List<T> or other collection. However, it adds a layer of abstraction and may have slightly more overhead than Array.Copy because it goes through the enumerator.

For most scenarios where you already have an array and want a full copy, Array.Copy or Clone() are more direct. ToArray() is a good choice when you are working with LINQ queries and want to materialize results into an array.

Another convenience is Array.ConstrainedCopy, which is similar to Array.Copy but guarantees that if an error occurs during the copy, the destination array is left unchanged. This is useful in security-sensitive or partial-trust scenarios, but for normal development Array.Copy is sufficient.

Manual Loops and Buffer.BlockCopy for Special Cases

Sometimes you need more control than the built-in methods offer. A simple for loop gives you the ability to transform elements during the copy, filter, or perform a deep copy.

int[] source = { 1, 2, 3 }; int[] target = new int[source.Length]; for (int i = 0; i < source.Length; i++) { target[i] = source[i]; }

This is straightforward and easy to modify. For example, you could copy only even numbers or apply a transformation.

For copying raw bytes, Buffer.BlockCopy copies bytes from one array to another. It is often used with byte[] arrays or when interoperating with unmanaged memory. It is extremely fast because it does not perform type checks or bounds checks per element, but it operates on byte offsets, not element indices.

byte[] source = { 1, 2, 3, 4 }; byte[] target = new byte[4]; Buffer.BlockCopy(source, 0, target, 0, source.Length);

Buffer.BlockCopy is not type-safe for non-byte arrays unless you know the element size and layout. For most array copy needs, Array.Copy is a better balance of safety and performance.

Shallow vs. Deep Copy: What Actually Gets Copied

The distinction between shallow and deep copy is critical when your array contains reference types. A shallow copy creates a new array but keeps references to the same objects. A deep copy clones the objects themselves, so the two arrays have no shared references.

class Person { public string Name { get; set; } } Person[] source = { new Person { Name = "Alice" } }; Person[] shallow = (Person[])source.Clone(); Person[] deep = new Person[source.Length]; for (int i = 0; i < source.Length; i++) { deep[i] = new Person { Name = source[i].Name }; }

In the shallow copy, shallow[0] and source[0] refer to the same Person instance. Changing shallow[0].Name also changes source[0].Name. In the deep copy, deep[0] is a new Person object, so modifications are independent.

Deep copying is not always necessary. If the objects in the array are immutable or if you intend to share them, a shallow copy is fine. But if you need to modify the objects independently, you must implement a deep copy. There is no built-in deep copy method in C#; you need to write your own cloning logic or use serialization.

Performance and Memory Considerations

Performance differences between copy methods are usually small for typical array sizes, but they can matter in hot paths. Array.Copy and Buffer.BlockCopy are the fastest because they are implemented at the CLR level and use efficient memory operations. Clone() is also fast but adds a type cast. LINQ ToArray() has slightly more overhead due to iterator machinery.

MethodSpeedMemory AllocationFlexibilityType Safety
Array.CopyFastDestination arrayHigh (range, index)Yes
Clone()FastNew arrayLow (full copy only)Requires cast
LINQ ToArray()ModerateNew arrayMedium (any IEnumerable)Yes
Manual loopVariableDestination arrayVery highYes
Buffer.BlockCopyFastestDestination arrayLow (byte-level)No

All methods allocate a new array (except when you reuse a pre-allocated destination with Array.Copy). If you are copying large arrays frequently, consider reusing the destination array to reduce garbage collection pressure.

For value-type arrays, Array.Copy and Clone() are equivalent in terms of data independence. For reference-type arrays, none of these methods perform a deep copy; you must implement that yourself.

Common Mistakes and How to Avoid Them

One common mistake is assuming that assignment creates a copy. As shown earlier, it only copies the reference. Another is forgetting to allocate the destination array before calling Array.Copy. If the destination is null or too small, you get an exception.

Another pitfall is using Clone() on a multi-dimensional array. Clone() performs a shallow copy of the top-level array, but for multi-dimensional arrays, the result is a new array with the same dimensions and element values. For jagged arrays (arrays of arrays), Clone() only copies the outer array, leaving the inner arrays shared.

int[][] jagged = new int[2][]; jagged[0] = new int[] { 1, 2 }; jagged[1] = new int[] { 3, 4 }; int[][] copy = (int[][])jagged.Clone(); copy[0][0] = 99; // modifies original jagged[0][0] as well

To copy jagged arrays deeply, you must iterate and clone each inner array separately.

Finally, when copying arrays of reference types, be aware that you are only copying references. If you need independent objects, implement a deep copy. This is often overlooked and leads to subtle bugs.

Choosing the Right Copy Method for Your Scenario

The method you choose depends on what you need. Use Array.Copy when you need a fast, type-safe copy of a range or when you want to reuse a pre-allocated destination. Use Clone() when you want a concise full copy and don't mind the cast. Use LINQ ToArray() when you are already working with LINQ or need to convert a non-array sequence. Use a manual loop when you need to transform elements or perform a deep copy. Use Buffer.BlockCopy only when you are dealing with raw bytes and need maximum speed.

For most everyday scenarios, Array.Copy is the most practical choice because it offers a good balance of performance, safety, and flexibility. It is also the method that most closely matches the mental model of "copying" an array in C#.

When performance is critical, avoid LINQ and manual loops for simple copies. But always measure with a profiler if you suspect array copying is a bottleneck; premature optimization is rarely worth the added complexity.

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