Elegant Array Filling in C#: From Java's Arrays.fill to C# Extension Methods

Dec 07, 2025 · Programming · 9 views · 7.8

Keywords: C# | Array Filling | Extension Methods

Abstract: This article provides an in-depth exploration of various methods to implement array filling functionality in C#, similar to Java's Arrays.fill, with a focus on custom extension methods. By comparing traditional approaches like Enumerable.Repeat and for loops, it details the advantages of extension methods in terms of code conciseness, type safety, and performance. The discussion also covers the fundamental differences between HTML tags like <br> and character \n, offering complete code examples and best practices to help developers efficiently handle array initialization tasks.

Introduction and Problem Context

In the Java programming language, the java.util.Arrays class provides approximately 18 static fill methods for assigning a specified value to each element of an array. This design significantly simplifies array initialization, avoiding repetitive loop code. However, when developers transition to C#, they may find that the standard library lacks a directly equivalent compact method. This article systematically analyzes multiple approaches to implement array filling in C#, with a primary recommendation for best practices based on extension methods.

Limitations of Existing Methods

Before exploring solutions, it is essential to examine several common alternatives in C# and their shortcomings:

  1. Limitations of ForEach: The Array.ForEach method passes copies of array elements (by value), preventing direct modification of the original array. This stems from differences in value type versus reference type passing mechanisms in C#.
  2. Overhead of Enumerable.Repeat: While Enumerable.Repeat(42, 10000).ToArray() can create a new filled array, this approach involves two memory allocations (generating an enumerable sequence and converting to an array) and element copying. For large arrays or performance-sensitive scenarios, this overhead may be non-negligible.
  3. Redundancy of Traditional for Loops: Direct use of for loops, though functionally complete, lacks code conciseness and expressiveness. This is precisely why Java introduced Arrays.fill—to enhance code readability through declarative syntax.
  4. Limited Applicability of Array.Clear: The Array.Clear method only sets array elements to their type default values (e.g., 0, null), and cannot specify arbitrary fill values. For scenarios requiring non-default values, this method is insufficient.

Core Implementation of Extension Methods

Based on the above analysis, custom extension methods emerge as the most elegant solution. The following code demonstrates a complete implementation of a generic Fill extension method:

public static class ArrayExtensions {
    public static void Fill<T>(this T[] originalArray, T with) {
        for (int i = 0; i < originalArray.Length; i++) {
            originalArray[i] = with;
        }
    }
}

Key features of this method include:

Usage Examples and Scenario Analysis

The following examples illustrate the application of extension methods in various contexts:

// Example 1: Integer array filling
int[] numbers = new int[5];
numbers.Fill(7); // All elements become 7

// Example 2: String array filling
string[] texts = new string[3];
texts.Fill("default"); // All elements become "default"

// Example 3: Custom type array filling
class Point { public int X; public int Y; }
Point[] points = new Point[10];
points.Fill(new Point { X = 1, Y = 2 }); // Note: All elements reference the same object instance

Special attention is required for reference type array filling behavior: when the fill value is a reference type, all array elements point to the same object instance. If independent instances are needed, new objects should be created within the loop:

public static void FillIndependently<T>(this T[] array, Func<T> factory) where T : class {
    for (int i = 0; i < array.Length; i++) {
        array[i] = factory();
    }
}
// Usage
points.FillIndependently(() => new Point { X = 1, Y = 2 });

Performance Comparison and Optimization Recommendations

A benchmark comparison of different methods reveals performance characteristics:

<table border="1"> <tr><th>Method</th><th>Time Complexity</th><th>Space Complexity</th><th>Applicable Scenarios</th></tr> <tr><td>Extension Method Fill</td><td>O(n)</td><td>O(1)</td><td>General scenarios, optimal performance</td></tr> <tr><td>Enumerable.Repeat</td><td>O(n)</td><td>O(n)</td><td>Requires new array, does not modify original</td></tr> <tr><td>for Loop</td><td>O(n)</td><td>O(1)</td><td>Essentially same as extension method but syntactically redundant</td></tr>

Optimization recommendations:

  1. For extremely large arrays (e.g., millions of elements), consider block copying optimizations using Array.Copy, but note type compatibility.
  2. When filling arrays in multithreaded environments, ensure thread safety or use parallel methods (e.g., Parallel.For).
  3. For frequently invoked scenarios, compile extension methods into dynamic delegates to enhance performance.

Comparison with Other Languages

Compared to Java's Arrays.fill implementation, C# extension methods offer the following advantages:

Similarly, Python's list * n syntax and JavaScript's Array.fill() method provide array filling functionality, but C#'s solution offers superior type safety and performance.

Conclusion and Best Practices

Implementing array filling functionality through custom extension methods not only addresses gaps in the C# standard library but also provides a more flexible and type-safe solution than Java's Arrays.fill. Developers are advised to:

  1. Include the ArrayExtensions class in a common utility library for cross-project reuse.
  2. Choose the appropriate filling strategy based on specific needs: extension methods for in-place modification, Enumerable.Repeat for new arrays.
  3. Be mindful of shared instance issues with reference type arrays, using factory methods when necessary.
  4. Validate the actual performance of different methods via benchmarks in performance-critical paths.

This pattern is not limited to array filling but can be extended to other collection types, fully demonstrating C#'s powerful capabilities in metaprogramming and syntactic sugar.

Copyright Notice: All rights in this article are reserved by the operators of DevGex. Reasonable sharing and citation are welcome; any reproduction, excerpting, or re-publication without prior permission is prohibited.