Updated on

An empty array in C# is Array.Empty<T>(), or [], which the compiler turns into the same thing. Both hand back one shared zero-length array instead of allocating a new one.

The older spellings still work. new string[0], new string[] { } and string[] myArray = { }; each allocate a new array every time they run, 24 bytes on a 64-bit runtime, unless the JIT sees that the array never leaves the method. That is cheap and still unnecessary for a value that can never change.

Arrays are used to store multiple variables of the same type. Sometimes our solution design may require the use of an empty array. For example, as an initial value for a dynamic-sized collection, or in cases where a method would usually return a list of results, an empty array could indicate no results. We shall use string arrays for our examples but the concept could be applied to the other datatypes as well.

Array.Empty<byte>() and byte[] empty = [];, for instance, declare an empty byte array the same way.

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

How Do We Declare an Empty Array With the new Keyword?

The new keyword gives us three spellings of the same thing, and all three build a brand new zero-length array.

new string[0] states the length directly. new string[] { } uses an empty initializer list. string[] myArray = { }; lets the declared type supply the element type.

Each spelling compiles to a real allocation. Measured on .NET 10.0.10 in Release, a method returning any of the three allocates 24 bytes per call, and two calls never hand back the same object: ReferenceEquals on their results is false every time.

Twenty-four bytes is the smallest an array can be on a 64-bit runtime: an object header, a method table pointer, and a length field with its padding. With no elements, nothing comes after them.

A value that can never change does not need a fresh copy each time. A zero-length array has nothing to write into, so every caller in the process can safely share one instance rather than asking the allocator for another.

Use a Length of Zero

We will start with one of the classic ways to initialize an array:

var myArray = new string[0];

A drawback of this method is that it allocates a new array of length 0 on every call, 24 bytes each time on a 64-bit runtime, unless the JIT sees that the array never leaves the method. That is not a lot, but in a method called in a loop it adds 24 bytes of garbage per iteration for a value that never changes.

Use an Empty Array Initializer

Next, we’ll see how to initialize the array using an empty array initializer:

var myArray = new string[] { };

Or:

string[] myArray = { };

This yields the same result as new string[0] but has the same drawback. It’s also slightly less readable.

To create an array that already holds values, see the other ways to initialize an array in C#.

How Does the [] Collection Expression Declare an Empty Array?

[] is a collection expression, and it is the shortest way to write an empty array in C#.

The compiler decides how to build it. Microsoft’s C# reference is explicit about the empty case: the empty collection expression “can be realized as Array.Empty<T>() if the target won’t be modified after initialization.” A zero-length array has nothing to modify, so that is what happens.

Measured on .NET 10.0.10, string[] myArray = []; allocates nothing, and ReferenceEquals against Array.Empty<string>() returns true. The two forms produce the same object.

So [] costs exactly what Array.Empty<T>() costs. It is the same call with the type name left out, which is why it reads well where the target type is already obvious, such as a field initializer or a ?? [] fallback.

It does need C# 12. Collection expressions arrived in that version, which shipped with .NET 8 in November 2023, and a project on an earlier language version rejects the syntax, with error CS9058 on C# 11.

Declaring an empty string array with it takes one line:

string[] myArray = [];

There is no element type in the expression, because the declaration on the left already supplies it.

Collection expressions do a lot more than declare empty arrays. Microsoft documents the full syntax in its collection expressions reference, and we walk through collection expressions and the spread element in their own article.

How Do We Create an Empty Array With the Enumerable Class?

Enumerable.Empty<string>().ToArray() and Enumerable.Repeat(string.Empty, 0).ToArray() both produce an empty string[], and both take the long way round to get there.

Neither one is slow. Measured on .NET 10.0.10, both allocate zero bytes and return the very same object that Array.Empty<string>() returns. Enumerable.Empty<T>() and Enumerable.Repeat() with a count of zero both hand back the cached Array.Empty<T>() array, and ToArray() on an empty collection returns that same array instead of allocating a new one.

The cost is reading time, not memory. Enumerable.Repeat(string.Empty, 0) asks for an empty string repeated zero times, which is a small puzzle to solve on the way to understanding that it means “nothing”.

Reach for Enumerable.Empty<T>() when the code wants an empty IEnumerable<T> rather than an array, for example as a fallback inside a LINQ expression or as the result of a query method that has nothing to return. Do not reach for either one to declare an empty array, because two shorter forms say it plainly.

Use the Empty Method

In this approach, we use LINQ to create an empty IEnumerable<string> sequence and then convert it to an array using the ToArray() method:

var myArray = Enumerable.Empty<string>().ToArray();

Use the Repeat Method

We show this one only for completeness. Do not use it to declare an empty array.

We can also use the Enumerable.Repeat() method to repeat the empty string 0 times and then convert it to an array using the ToArray() method:

var myArray = Enumerable.Repeat("", 0).ToArray();

Or:

var myArray = Enumerable.Repeat(string.Empty, 0).ToArray();

None of the three Enumerable versions allocates anything on .NET 10, for the reasons given at the top of this section. What they cost is clarity: each takes a detour through LINQ to arrive at a value that Array.Empty<string>() states directly.

Why Is Array.Empty<T>() the Default Choice?

Array.Empty<T>() returns a cached zero-length array of T. Every call for the same T gives back the same object, so one allocation serves the whole process.

var myArray = Array.Empty<string>();

Microsoft Learn lists the method from .NET Framework 4.6, .NET Core 1.0 and .NET Standard 1.3 onward, which makes it available in essentially every project we are likely to open, including ones far too old for [].

It also says what it means. new string[0] describes a length that happens to be zero, while Array.Empty<string>() describes an intention, which is what a method returning no results wants to say.

Because every caller holds the same instance, an array from Array.Empty<T>() is not a useful lock target and not a reliable marker for reference comparison: ReferenceEquals reports two unrelated empty arrays as the same object. Sharing it carries no thread-safety risk, since there is nothing in it to write to.

When a read-only view is enough and an array is not required, ReadOnlySpan<T>.Empty is the equivalent.

Here are all the forms side by side, each returned from a method and measured on .NET 10.0.10 in Release on a 64-bit runtime:

How it is writtenAllocates per call (64-bit)Same instance every callUse it when
Array.Empty<string>()0 bytesYesAlways, unless the syntax below is shorter to read
string[] myArray = [];0 bytesYesC# 12 or later; the compiler emits Array.Empty<string>()
new string[0]24 bytesNoLegacy code, or a target older than .NET Framework 4.6, which has no Array.Empty
new string[] { }24 bytesNoNever in new code: it costs the same as the row above
string[] myArray = { };24 bytesNoNever in new code: it costs the same as the row above
Enumerable.Empty<string>().ToArray()0 bytesYesA LINQ chain already needs an empty sequence
Enumerable.Repeat(string.Empty, 0).ToArray()0 bytesYesNever; it says "repeat zero times" to mean "nothing"
ReadOnlySpan<string>.Empty0 bytesn/a (a struct)A read-only view is wanted, not an array

The two LINQ rows match Array.Empty<string>() because of how the .NET 10 libraries implement Enumerable.Empty(), Enumerable.Repeat() and ToArray(), so the 0 bytes and Yes in those two rows are a measurement of this runtime’s implementation.

Once the array exists, adding and appending values to it is a different job, and a shorter one than it looks.

Conclusion

We have looked at five ways to declare an empty array in C#, and they do not all cost the same. Array.Empty<T>() and [] return one shared instance and allocate nothing. The three new spellings allocate a fresh array on every call, 24 bytes on a 64-bit runtime, unless the JIT sees that the array never leaves the method.

On C# 12 or later, write [] where the target type is obvious and Array.Empty<T>() where it is not. Both compile to the same thing, so the choice between them is about reading, not about speed.

When the collection has to grow after we create it, start with an empty List<T> instead of an array.

Tested with .NET 10.0.10 (SDK 10.0.302).