Updated on

To set every element of a C# array to one value, we call Array.Fill(array, value). It writes the value into each element of an array we already have, in a single call. Enumerable.Repeat() and a plain for loop get the same result.

We’re going to explore these built-in techniques, write our own approach, and finish with a performance benchmark on .NET 10 to check which one is the fastest and why.

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

There are a lot of topics to cover in this article, so let’s start preparing our environment.

Preparing the Environment

Initially, 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, inside a class, we should create a method to return a new instance of the article’s array and set its size to 10 elements:

public static Article[] InstantiateInitialArray()
{
    return new Article[10];
}

Once we have our class and our array ready, let’s start populating it.

How Does Array.Fill Work in C#?

Array.Fill() is a static, generic method on the Array class that writes one value into every element of an existing array. It returns nothing and changes the array in place, so there is no new array to assign back.

A second overload takes a start index and a count and fills only that range. A range past the end of the array throws an ArgumentOutOfRangeException.

The method arrived with .NET Core 2.0 and .NET Standard 2.1, so every current .NET version has it. .NET Framework and .NET Standard 2.0 don’t.

With a value type such as int, every element gets its own copy. With a reference type such as our Article, every element points to the same object, so a change made through one index shows up at all of them.

When the value we want is the type’s default, such as 0 or null, we can skip Array.Fill(), because a new array already starts out filled with defaults.

Microsoft Learn sums the method up in one line, “Assigns the given value of type T to each element of the specified array”, and the call looks like this:

Array.Fill(array, value);

The first parameter represents the array we want to fill, and the second represents the value we want to assign to each index of this array. This is a generic and static method, which means we can use this method with arrays of any object type, and we don’t need to instantiate the Array class to use it. 

Besides those two parameters, it is worth mentioning that the Fill method provides an overload where we can pass a start index and a count variable, both integers. When we call this method passing these two additional parameters, the result is going to be a little different:

Array.Fill(array, value, 5, 2);

Here, once we send 5 as the start index and 2 as the count, our array is going to keep all the previous values, except for indexes 5 and 6. These indexes are going to receive the new value that is represented as our second parameter. 

Can We Use Array.Fill in .NET Framework or .NET Standard 2.0?

No. Array.Fill() arrived with .NET Core 2.0 and .NET Standard 2.1, and .NET Framework never got it. A library that targets .NET Standard 2.0, or an app on .NET Framework 4.8, fails to compile the call with error CS0117, “‘Array’ does not contain a definition for ‘Fill'”.

On those targets, a plain for loop does the same job, and so does Enumerable.Repeat(), which .NET Framework has had since version 3.5.

If the project references the System.Memory package, we can fill through a span instead:

var articles = new Article[10];
articles.AsSpan().Fill(article);
articles.AsSpan(5, 2).Fill(article);

The first call fills the whole array, and the second fills only indexes 5 and 6, just like the Array.Fill() overload. This form works on modern .NET too, where Array.Fill() itself hands most arrays to Span<T>.Fill(). To learn more about spans, check out how to use Span in C# to improve application performance.

Using Enumerable.Repeat to Populate an Array in C#

Under the System.Linq namespace, we have Enumerable.Repeat. Let’s check how to use it:

var articles = Enumerable.Repeat(value, 10).ToArray();

Similar to the method above, this is a static and generic method, however, it doesn’t receive an array as a parameter, but the value we want to repeat and an integer to represent the number of times we want to repeat (count).

It requires that our last parameter (count) is not negative, otherwise, it throws an ArgumentOutOfRangeException. A count of zero is fine and gives us an empty sequence.

This method returns an IEnumerable<T>, not an array. Since we want our result as an array, we convert it with ToArray(). If we need a list instead, ToList() gives us a List<T> with the same values.

Similar to the Array.Fill() approach, this technique gives us a shallow copy of the elements. It means that, when we change any property’s value of the element we used to fill this array, this change is going to propagate through the entire array. That happens because .NET is not creating a new element for each index, but, referencing the same element every time.

Using Iteration Statement to Populate an Array in C#

Let’s create a new ForStatement method in an ArrayPopulator class to see how we can populate an array using simple iteration:

public Article[] ForStatement(Article[] articles, Article article)
{
    for (int index = 0; index < articles.Length; index++)
    {
        articles[index] = new Article
        {
            Title = article.Title,
            LastUpdate = article.LastUpdate
        };
    }

    return articles;
}

Our method returns an array of articles and receives two input parameters. The first represents the array that we want to fill and the second parameter is the element we are going to use to fill our array.

First, we start a loop iterating through the entire array (articles.Length). Then, within every iteration, we assign a new Article instance to each index of the array.

Note that for each iteration, we are instantiating a new article. Otherwise, if we just assign the article we receive as a parameter, every index of our array will reference the same element. This means once we change the Title or the LastUpdate from one object in the array, all indexes are going to receive this change.

Copying two properties by hand gives us fully independent elements here, because Article holds only a string and a DateTime. When an object carries nested references, we need a real deep copy, and our article on how to deep copy an object in C# covers the options.

Instantiating and Populating a Very Small Array

If we don’t mind a bit of typing and our array is very small, there’s an easier form to achieve the same results we previously studied:

public Article[] InstantiateArrayManually()
{
    return
    [
        new() { Title = "How to Copy Array Elements to New Array in C#", LastUpdate = new DateTime(2022, 01, 31) },
        new() { Title = "How to Copy Array Elements to New Array in C#", LastUpdate = new DateTime(2022, 01, 31) }
    ];
}

Here, we create a new method that returns our array of articles filled with the elements.

The square brackets are a collection expression, and new() lets the compiler work out the Article type from the array. For the other ways to create an array with its values up front, check out how to initialize arrays in C#.

Benchmark

Let’s implement a performance benchmark to show the difference between the above approaches.

First, we are going to create an array with 100 thousand elements and an object that will fill all these positions. We also mark the class with BenchmarkDotNet’s [MemoryDiagnoser] attribute, so the results show how much memory each approach allocates:

[MemoryDiagnoser]
public class ArrayPopulatorBenchmark
{
    private static readonly ArrayPopulator _arrayPopulator = new();
    private readonly Article[] _benchMarkArray = new Article[100_000];
    private readonly Article _benchmarkArticle = new()
    {
        Title = "How to Copy Array Elements to New Array in C#",
        LastUpdate = new DateTime(2022, 01, 31)
    };

    // one [Benchmark] method per approach
}

To make it easier to read, instead of writing 100000, we use the digit separator and write 100_000. If [MemoryDiagnoser] is new to you, our article on memory allocation optimization with BenchmarkDotNet explains what it measures.

The class goes in its own console project, which references the project that holds our Article and ArrayPopulator classes. We add the BenchmarkDotNet package to it, start the class file with using BenchmarkDotNet.Attributes;, and call BenchmarkRunner.Run<ArrayPopulatorBenchmark>(); from its Program.cs, after using BenchmarkDotNet.Running;. After running our benchmark in Release mode, we can inspect the result:

| Method                  | Mean       | Error    | StdDev   | Gen0     | Gen1     | Gen2     | Allocated |
|------------------------ |-----------:|---------:|---------:|---------:|---------:|---------:|----------:|
| FillArray               |   304.4 us |  6.00 us |  9.86 us |        - |        - |        - |         - |
| EnumerableRepeat        |   560.7 us | 10.90 us | 11.19 us | 249.0234 | 249.0234 | 249.0234 |  800148 B |
| ForStatement            | 2,211.4 us | 43.89 us | 99.07 us | 378.9063 | 375.0000 |        - | 3200000 B |

The fastest technique is Array.Fill(). It is about 1.8 times faster than Enumerable.Repeat and about 7.3 times faster than when we use the iteration loop.

The Allocated column shows where the difference comes from. Array.Fill() writes into the array we already have and allocates nothing. Enumerable.Repeat builds a new array of 100,000 elements on every call (800,148 bytes allocated in all), and on .NET 10 its ToArray() then fills that new array by calling Array.Fill() itself. ForStatement creates 100,000 new Article objects (3,200,000 bytes) per call.

On the other hand, the ForStatement method is the only one that does a deep copy of elements.

Once our ForStatement showed us results far worse than any other techniques, we are going to create a new method and try the same for statement, this time, using a shallow copy. Let’s create this new method:

public Article[] ForStatementShallowCopy(Article[] articles, Article article)
{
    for (int index = 0; index < articles.Length; index++)
    {
        articles[index] = article;
    }

    return articles;
}

With the new method in place, here are the full results:

| Method                  | Mean       | Error    | StdDev   | Gen0     | Gen1     | Gen2     | Allocated |
|------------------------ |-----------:|---------:|---------:|---------:|---------:|---------:|----------:|
| FillArray               |   304.4 us |  6.00 us |  9.86 us |        - |        - |        - |         - |
| EnumerableRepeat        |   560.7 us | 10.90 us | 11.19 us | 249.0234 | 249.0234 | 249.0234 |  800148 B |
| ForStatement            | 2,211.4 us | 43.89 us | 99.07 us | 378.9063 | 375.0000 |        - | 3200000 B |
| ForStatementShallowCopy |   362.1 us |  6.30 us |  9.24 us |        - |        - |        - |         - |

Note that, the ForStatementShallowCopy is much faster compared with the ForStatement method. It allocates nothing, just like Array.Fill(), and lands close to it.

Here is how the approaches compare side by side:

ApproachFills an existing array?Reference types: one shared object?AllocatesAvailable on
Array.Fill(array, value)YesYesNothing.NET Core 2.0 and later, .NET Standard 2.1
array.AsSpan().Fill(value)YesYesNothing.NET Core 2.1 and later, .NET Standard 2.1, or the System.Memory package
Enumerable.Repeat(value, count).ToArray()No, returns a new arrayYesA new array.NET Framework 3.5 and later, every .NET
for loop, articles[index] = articleYesYesNothingEverywhere
for loop, articles[index] = new Article { ... }YesNo, one object per elementOne object per elementEverywhere

For most code, Array.Fill() is the one to reach for. The loop that creates a new object per element is the choice when every element must be its own object, and the price is the allocations we just measured.

Conclusion

In this article, we’ve seen five different approaches to populate arrays and a performance benchmark that helps us to choose the best option depending on our needs. Also, we’ve seen that shallow copy is much faster than deep copy, however, we should understand the problem we want to solve to apply the correct technique.

On .NET 10, Array.Fill() is still the fastest of them, and the loop that creates a new object per element is still the one to use when the elements must not share an object.

Tested with .NET 10.0.10, BenchmarkDotNet 0.15.8 and MSTest 4.5.1.