In this article, we are going to learn how to copy array elements to a new array in C#. We are going to see many different ways to accomplish this task, and at the end, we will do a benchmark to check which is the best way to copy elements from one array to another.

To download the source code for this article, you can visit our GitHub repository.

Let’s start.

Instantiating the Initial Array

First, let’s create a class that is going to represent the elements of our array:

public class Article
{
    public string? Title { get; set; }
    public DateTime LastUpdate { get; set; }

    public override string ToString()
    {
        return $" Title: {Title} | Last update:{LastUpdate}";
    }
}

Next, let’s create some Article objects and then fill our source array:

var article1 = new Article { Title = "C# Intermediate – Delegates" };
var article2 = new Article { Title = "Events in C#" };
var article3 = new Article { Title = "Selection Sort in C#" };

var initialArray = new Article[] { article1, article2, article3 };

Now that we have our initialArray ready, let’s try some approaches.

Copying Elements by Assignment

The first and easiest way to copy values from one array to another is by copying the entire array by assignment (using = operator):

var destination = initialArray;

However, this is not always a good solution. Since arrays work as a reference type, when we change a value inside the initialArray (or vice-versa), both arrays will change. In other words, we are not creating a new array, we are just using two variables pointing to the same memory address.

That said, let’s solve this problem with our next approach.

Copying Elements Using Array.Copy

This approach uses a static method from the Array class that lives under the System namespace.

So, let’s create our destinationArray and use the Copy method:

Article[] destinationArray = new Article[initialArray.Length];
Array.Copy(initialArray, destinationArray, initialArray.Length);

This method copies a range of elements depending on the parameters we pass. The first and the second parameters represent our source and destination array. The third parameter, specified as int or long, is the number of elements we are going to copy. In this case, we are copying all the elements from the source array.

If we don’t need to copy an entire array, the Array class provides an overload to this method:

Array.Copy(initialArray, 1, destinationArray, 0, initialArray.Length - 1);

Both first and second parameters are about the source array, representing the source array and the index that the copy will begin. The third and the fourth parameter represents, respectively, the destination array and the index at which storing begins. The last parameter is the number of elements to copy.

In this scenario, our destinationArray will consist of the second and third elements from the initialArray and our third slot will be empty:

EmptySlot After Array.Copy

Copying Elements Using Clone

When we use the Clone method, it will return a shallow copy of the System.Array. In other words, our destination array will have references to the elements of our source array.

Let’s implement our clone:

var destinationArray = (Article[])initialArray.Clone();

This method doesn’t return an array, but an object. Hence, we can’t iterate with our resulting array unless we cast it to the required type. In this case, we use (Article[]) to cast.

This method doesn’t allow us to make a partial copy from the source array.

Copying Elements Using CopyTo

This approach is very similar to the method above. However, different from the Clone, we will need to provide some input parameters and we are not going to receive any return type.

Let’s instantiate our destination array of articles and set its size:

var destinationArray = new Article[initialArray.Length];

Then, let’s copy the elements from the source array:

initialArray.CopyTo(destinationArray, 0);

The first parameter represents the array that will receive the elements. The second represents the index in the destinationArray that will start receiving elements.

Using Range to Copy Array Elements

Microsoft introduced the range concepts since C# 8.0, and this is another way we can use to copy elements from one array to another.

With this technique, we can specify the initial and the final index we want to copy within the brackets:

var destinationArray = initialAr1..ray[1..3];

In this example, our destinationArray will receive the elements starting from index 1 up to index 3 (index 3 not inclusive).

On the other hand, if we want to copy the array by complete, we don’t need to specify the range between brackets[..]:

var destinationArray = initialArray[..];

Copying Array Elements Using Linq

We can use Linq to achieve this result:

var destinationArray = initialArray.Select(x => x).ToArray();

We use the Select method to project our array to IEnumerable<TResult>.

If we want a deep copy of our elements, we may implement a simple change in the lambda expression to create a new instance or Article:

var destinationArray = initialArray
    .Select(x => new Article { Title = x.Title, LastUpdate = x.LastUpdate })
    .ToArray();

Copying Elements Manually

Finally, we are going to copy elements using iteration statements. In this case, we are going to use the for loop.

Let’s define our destination array:

var destinationArray = new Article[initialArray.Length];

And now, let’s implement our for statement:

for (int index = 0; index < initialArray.Length; index++)
    destinationArray[index] = new Article 
    { 
        Title = initialArray[index].Title,
        LastUpdate = initialArray[index].LastUpdate
    };

return destinationArray;

As in the Linq approach, in this implementation, we are instantiating a new Article on each iteration to create a deep copy of elements. 

Benchmark

To define which is the best way to copy elements from one array to another, we’ve prepared two benchmarks to compare all of the above methods.

For the first benchmark, we are going to create an array of 1000 elements:

Article[] benchMarkSourceArray = Enumerable
    .Repeat(..., 1000)
    .ToArray();

And then, run the benchmark:

|              Method |           Mean |       Error |      StdDev |         Median |
|-------------------- |---------------:|------------:|------------:|---------------:|
| CopyUsingAssignment |      0.0013 ns |   0.0024 ns |   0.0036 ns |      0.0000 ns |
| CopyUsingArrayClass |    939.1099 ns |  18.5723 ns |  34.4250 ns |    926.3531 ns |
|      CopyUsingClone |    976.6282 ns |  19.4959 ns |  41.9671 ns |    983.8374 ns |
|     CopyUsingCopyTo |    960.8490 ns |  19.1351 ns |  35.4682 ns |    947.5609 ns |
|      CopyUsingRange |    930.2984 ns |  18.4262 ns |  42.7056 ns |    924.9545 ns |
|       CopyUsingLinq | 13,222.5013 ns | 263.1865 ns | 609.9747 ns | 12,948.8930 ns |
|        ManuallyCopy | 11,207.3473 ns |  87.2290 ns | 107.1251 ns | 11,204.0741 ns |

After that, we are going to run a new benchmark with an array of 10 000 elements:

|              Method |            Mean |         Error |        StdDev |          Median |
|-------------------- |----------------:|--------------:|--------------:|----------------:|
| CopyUsingAssignment |       0.0067 ns |     0.0127 ns |     0.0215 ns |       0.0000 ns |
| CopyUsingArrayClass |  10,752.9637 ns |   204.2407 ns |   465.1594 ns |  10,628.2700 ns |
|      CopyUsingClone |  10,927.4929 ns |   218.2734 ns |   339.8253 ns |  10,901.4664 ns |
|     CopyUsingCopyTo |  11,133.5772 ns |   220.8639 ns |   323.7394 ns |  11,096.6270 ns |
|      CopyUsingRange |  10,589.9803 ns |   202.9573 ns |   395.8526 ns |  10,535.3569 ns |
|       CopyUsingLinq | 185,915.4630 ns | 3,506.8051 ns | 6,586.6299 ns | 185,597.4731 ns |
|        ManuallyCopy | 167,206.4378 ns | 3,311.6700 ns | 8,247.2076 ns | 165,802.4780 ns |

Analyzing these benchmark results, note that our first method CopyUsingAssignment is way faster than all other methods. It happens because we are not copying the array elements, we are just creating a new array and referencing our source array.

Except for ManuallyCopy and CopyUsingLinq methods, we are not having a big difference with other methods, which implies that we are free to choose the one we like more. But we must take into account whether we need a deep copy or not.

Comparing that two benchmarks, we note that it doesn’t matter how large the arrays are. It slightly affects the CopyTo method but overall, the execution time grows proportionally to the array’s size.

Conclusion

In this article, we have learned many ways to copy elements from one array to another, using deep and shallow copy. 

We have seen a benchmark comparison between them that leads us to choose the best method when we are writing our code.