ImmutableArray empty collection initializer is not equal to ImmutableArray.Empty in C# 12

Abstract: Resolve unexpected reference inequality failures when comparing empty ImmutableArray instances by using the singleton Empty property instead of collection initializers.

Created: 2026-09-17 by
Using an empty collection initializer on ImmutableArray creates a new, distinct instance with default equality semantics, whereas ImmutableArray.Empty is a cached singleton. In C# 12, relying on the initializer for empty checks can lead to unexpected reference inequality failures because each initialization allocates a separate object in memory rather than reusing the global empty state.

The Core Distinction Between Singleton and Instance

The primary difference lies in how these two constructs handle memory allocation and identity. ImmutableArray<T>.Empty is a static readonly field that provides a pre-allocated, read-only array instance. This singleton pattern ensures that every time you access Empty, you get the exact same object reference back. This is highly efficient for memory usage and allows for fast reference equality checks using ReferenceEquals. In contrast, when you use the collection initializer syntax like new ImmutableArray<int>() { }, the compiler generates code that calls the constructor and potentially sets up internal fields to represent an empty state. While the resulting array contains zero elements, it is a newly allocated object. Each time this syntax appears in your code, a new heap allocation occurs. This means that two variables initialized this way will not be reference-equal, even though they both logically represent an empty collection. This distinction is crucial in performance-sensitive applications or when dealing with large numbers of empty collections. The overhead of allocating many small objects can contribute to garbage collection pressure. By using the singleton Empty property, you eliminate this allocation entirely. It is important to note that while the values inside are identical (both are empty), their identities are fundamentally different. One is a shared resource, and the other is a unique instance.

Behavior of Equality Checks

When working with ImmutableArray, developers often rely on equality operators to determine if two arrays contain the same data. Understanding the behavior of these operators helps avoid subtle bugs. The == operator for ImmutableArray performs a structural comparison by default. This means it checks if the lengths are equal and if all corresponding elements are equal. Since both an empty initializer and Empty have a length of zero, the structural equality check returns true. However, reference equality behaves differently. If you use ReferenceEquals or check identity in a context where object identity matters, the results will diverge. ReferenceEquals(ImmutableArray<int>.Empty, ImmutableArray<int>.Empty) returns true because it is the same object. Conversely, comparing two instances created via initializers will return false. This can cause issues in hash-based collections if you inadvertently use the array itself as a key without proper hashing overrides, although ImmutableArray typically handles hashing based on content. It is also worth noting that ImmutableArray implements IEquatable<ImmutableArray<T>>. The Equals method follows the same structural logic as the == operator. Therefore, for most logical comparisons, both approaches yield the same result regarding content. The danger arises when code assumes that an empty collection must be the specific singleton instance, perhaps for optimization purposes or strict identity checks.

Performance Implications in C# 12

C# 12 introduces various improvements to language features, but the underlying behavior of ImmutableArray initialization remains consistent with previous versions. The performance gap between using the singleton and the initializer becomes significant only when dealing with high-frequency allocations. In typical application logic, the difference might be negligible. However, in tight loops or systems processing millions of records, the allocation cost adds up. Using ImmutableArray.Empty is generally recommended when you know the collection will be empty. It avoids the overhead of constructor calls and memory allocation. If you are building a collection dynamically and start empty, consider initializing it with Empty and then using methods like Add or creating a new immutable array from a list. This approach leverages the immutability model effectively while minimizing unnecessary object creation. For scenarios where you need a mutable builder, ImmutableArray.CreateBuilder is the appropriate choice. It allows you to add items efficiently before calling ToImmutable(). If the builder ends up empty, calling ToImmutable() on an empty builder may still return a new instance depending on the implementation details, so checking against Empty explicitly can be a good practice for normalization.

Best Practices for Developers

To maintain clean and efficient code, always prefer ImmutableArray<T>.Empty when you intend to represent a known empty collection. Reserve the collection initializer syntax for cases where you are populating the array with specific values at declaration time. For example, new ImmutableArray<int>() { 1, 2 } is perfectly valid and necessary for inline definition. But for an empty state, new ImmutableArray<int>() { } is redundant and wasteful. Additionally, be cautious when writing unit tests that rely on reference equality for empty collections. Ensure your test assertions account for structural equality unless you are specifically testing for the singleton pattern. If you are designing APIs that accept ImmutableArray, document whether the caller should pass Empty or if any empty structure is acceptable. This clarity prevents misuse and ensures consistent behavior across the system. For more information on managing state and memory in C#, you might find insights in Would a static variable in an instance class cause a memory leak in C?, which discusses similar patterns of static caching and reference management.

Frequently Asked Questions

Does using the collection initializer cause a memory leak?

No, it does not cause a memory leak. The allocated objects are short-lived and will be collected by the garbage collector. However, it increases garbage collection pressure due to the higher number of objects being created compared to using the singleton.

Can I use ImmutableArray.Empty with generic types?

Yes, ImmutableArray.Empty is generic. You can assign it to any ImmutableArray<T> variable, such as ImmutableArray<string>.Empty. The type parameter is inferred or specified explicitly, ensuring type safety without runtime errors.

Is there a performance benefit to using Empty in loops?

Yes, in tight loops where empty collections are frequently created, using Empty eliminates allocation overhead. This reduces CPU cycles spent on memory management and improves overall throughput, especially in high-performance computing scenarios.

What happens if I mix Empty and initializers in a list?

They coexist normally. A list containing both ImmutableArray.Empty and an empty initializer instance will have two distinct items. Structural operations like sorting or searching based on content will treat them as equivalent, but reference-based operations will see them as different objects.

Should I always check for null instead of Empty?

ImmutableArray is a value type and cannot be null. You should check for emptiness using the Length property or the IsEmpty property. Comparing against Empty is valid for structural equality but not required for correctness unless you need reference identity.

Latest News

How to Display Output of xterm Command in Terminal Screen using Cron

Resolve the inability to display xterm output in a terminal screen from cron by redirecting logs or using wall instead of insecure X11 workarounds.

Read More
Expose Local Server on VPS Preserving Real Client IPs (OS Level)

Resolve VPS logging showing only gateway IPs by configuring reverse proxies to forward real client addresses via X-Forwarded-For headers.

Read More
How to Clear Recent Files History in Linux without Deleting Actual Files?

Clear recent files history in Linux by deleting ~/.local/share/recently-used.xbel without removing the actual files.

Read More
Best HDD Copy Strategy: Manually Syncing and Rewriting Scratch

Resolve data drift between two 4TB hard drives by using rsync with the --delete flag to manually sync and rewrite scratch data for an exact mirror.

Read More
Understanding Bash Prompt Abbreviations: An Overview

Resolve repetitive typing errors by creating and persisting Bash aliases in the .bashrc file for improved command-line efficiency.

Read More
Free Tools and Methods to Log Real-Time Performance Details in Task Manager

Log real-time CPU and memory metrics to CSV files using Windows Performance Monitor Data Collector Sets to troubleshoot system slowness.

Read More
Contact Qatar Airways Customer Service: Phone Number, Help Center, and More

Resolve urgent Qatar Airways reservation issues like flight changes and baggage claims using the US phone number +1801-855-5905 or online self-service tools.

Read More
Windows 11: Alt Codes Displaying Wrong Characters - Solutions

Resolve Windows 11 Alt codes showing wrong characters by verifying the US keyboard layout and enabling Num Lock.

Read More
Run Programs with Elevated Privileges: A Comprehensive Guide

Eliminates the need to type sudo for frequent administrative tasks by configuring .bashrc aliases or functions.

Read More
Dynamically Changing Dates in Excel Formulas Using Cells

Eliminate manual date updates in Excel by using cell references to create dynamic formulas that automatically adjust calculations when input dates change.

Read More
Granting Edit Access to a Specific Excel Sheet in an Office 365 User Email ID-Based Login

Excel Online lacks native sheet-level permissions, so users must split workbooks or use worksheet protection to isolate edit access for specific tabs.

Read More
Creating Network Load on Local Wi-Fi from One PC

Generate sustained Wi-Fi bandwidth load from a single PC using a VM SFTP server to test router stability and throughput.

Read More
Changing the Default Editor for Batch Files in Windows 11's File Explorer

Resolve the issue of batch files opening in Notepad by changing the default editor to a preferred application like VS Code.

Read More
Gain WiFi Connection Minutes Before Losing it by Changing MAC Address

Bypass MAC address filtering to restore WiFi connectivity temporarily when a device is blocked by network administrators.

Read More
Photos Folders Turned Black: Troubleshooting Picture Applications on Windows

Resolve black screens in Windows Photos by resetting the app, updating graphics drivers, and repairing system files.

Read More
Troubleshooting High CPU Temperature Values: A Step-by-Step Guide

Resolve high CPU temperatures and thermal throttling by monitoring with Speedfan, cleaning dust from cooling components, and replacing degraded thermal paste.

Read More
Make cURL establish TLS connection with CA unknown

Resolve cURL TLS connection failures with unknown or self-signed certificates by using the --insecure flag to bypass CA validation.

Read More
Troubleshooting Incorrect Network Metrics Values in Grafana, Prometheus, InfluxDB, and Telegraf

Fix incorrect network metrics in Grafana, Prometheus, InfluxDB, and Telegraf by verifying interface selection, resolving unit mismatches, and handling counter resets.

Read More
Start Another Terminal Window (cmd.exe) Windows Repair/Troubleshoot

Provides step-by-step instructions to access the Windows Command Prompt via bootable media for advanced system repair and troubleshooting.

Read More
Thinkpad P1 Gen 6: Sudden Thunderbolt 3 Dock USB-C Charging Stopped Working

Resolve sudden Thunderbolt 3 dock USB-C charging and internet failure on ThinkPad P1 Gen 6 by updating firmware, resetting the dock, and adjusting power settings.

Read More
ASUS Windows 11 Laptop: Internet Connection Issue with Hotspot

Resolve ASUS Windows 11 laptop spinning wheel issue when connecting to mobile hotspot by resetting network stack, disabling IPv6, and adjusting power settings.

Read More
Developing iOS Project with Firebase: Logging in and Sending Push Notifications

Integrates Firebase to enable secure user authentication and push notifications in iOS applications.

Read More
Troubleshooting Bash Script with Suspected Issues of Spaces, Dashes, Filenames and Quoting

Resolve Bash script failures caused by word splitting, globbing, and special characters in filenames by applying proper quoting techniques.

Read More
Populating OneDrive Folder for Local Backup without Affecting Remote Files

Prevent OneDrive from deleting remote files during Windows reinstallation by unlinking the account or using symbolic links to isolate local data.

Read More
Force First Frame as Keyframe Without Re-encoding: A Quick Solution

Resolve inaccurate seeking and playback glitches by re-encoding video to ensure the first frame is a valid keyframe.

Read More
Find Information in Database Using WSL (Ubuntu) on Windows-10

Resolve database connection issues from WSL Ubuntu on Windows 10 by configuring client tools and network access to query remote or local servers.

Read More
Configuring a New Router with Different Networks: One Family, One Guest

Resolve IP conflicts and isolate guest traffic by configuring a second router with a distinct subnet via its WAN port.

Read More
Quickly Open Multiple Stock Websites with a Single Command

Solve the problem of manually opening multiple stock research websites by creating a single command to launch them simultaneously on Windows, macOS, or Linux.

Read More
Improved Adobe Acrobat Search Experience: Access Advanced Search with Ease

Access advanced search filters like case sensitivity and regex in Adobe Acrobat by clicking More Options in the Find bar.

Read More
Port Forwarding VM via OpenVPN: A Comprehensive Guide

Configure OpenVPN server and iptables to forward specific ports from VPN clients to a virtual machine's internal IP address.

Read More
Understanding Partitions in the 1980s: A Look Back at MS-DOS and Master Boot Record

Explains how the Master Boot Record and partition table enabled MS-DOS to manage multiple disk volumes on a single physical drive.

Read More
Windows 10 Enterprise: Keyboard Not Detected in Managed Organization with Admin Privileges

Resolve Windows 10 Enterprise keyboard detection failures caused by Group Policy restrictions, driver corruption, or USB enumeration errors.

Read More
Can't Find x86_64 Versions of Applications on MacOS arm64 (M1)

Resolve missing x86_64 app issues on M1 Macs by installing Rosetta 2 and reinstalling apps as universal binaries.

Read More
How to Hide Installation Source for an Android App

Manage Android app installation source visibility by using USB transfers or file managers to reduce browser traces and isolate data via work profiles.

Read More
Connecting Momentus 4200.2 ST9808210A Hard Drive via USB Cable

Resolve inability to access Seagate Momentus 4200.2 ST9808210A hard drive by connecting it via USB using a compatible SATA-to-USB adapter and configuring the disk in Windows.

Read More