Implementing AddRange for Collections in C#: A Comprehensive Analysis

Dec 03, 2025 · Programming · 8 views · 7.8

Keywords: C# | Collection Operations | Extension Methods

Abstract: This article provides an in-depth analysis of implementing the AddRange extension method for the ICollection<T> interface in C#. Focusing on the best answer's simple loop-based approach and supplementing with insights from other answers on performance optimization and .NET version features, it explores elegant solutions for adding ranges of elements under read-only property constraints. The article compares the pros and cons of different implementations, including direct foreach loops, leveraging List<T>.AddRange for performance, and the use of ForEach in .NET 4.5, offering practical technical guidance for developers.

Introduction

In C# programming, collection operations are a common requirement in daily development. When dealing with a class that inherits from Collection<T> and needs to add all elements from another collection to an existing collection via a read-only property, developers often seek more elegant solutions than simple foreach loops. While the List<T> class provides an AddRange method, it is specific to concrete List<T> instances and cannot be directly applied to the more general ICollection<T> interface. This raises a core question: how to implement an AddRange-like functionality for ICollection<T>, especially in a C# 3.0-friendly environment?

Basic Implementation Approach

The most straightforward method is to add AddRange functionality to the ICollection<T> interface through an extension method. As shown in the best answer, a simple and effective implementation uses a foreach loop to iterate through the source collection and add each element to the destination collection. Here is an example code snippet:

public static class CollectionHelpers
{
    public static void AddRange<T>(this ICollection<T> destination,
                                   IEnumerable<T> source)
    {
        foreach (T item in source)
        {
            destination.Add(item);
        }
    }
}

The key advantage of this approach is its generality and simplicity. It does not depend on any specific collection type, only requiring the destination to implement the ICollection<T> interface, making it applicable to various collection classes, including custom ones. From a design perspective, this avoids reinventing the wheel by extending existing interfaces, aligning with C# language features. However, it is important to note that each call to the Add method may require the collection to adjust its internal capacity, potentially leading to performance overhead, especially when adding a large number of elements.

Performance Optimization Strategies

To address performance concerns, other answers propose optimization strategies. A common approach is to check if the destination collection is of type List<T> and, if so, directly call its built-in AddRange method to leverage its optimized internal implementation. Here is an improved extension method example:

public static void AddRange<T>(this ICollection<T> destination,
                               IEnumerable<T> source)
{
    List<T> list = destination as List<T>;

    if (list != null)
    {
        list.AddRange(source);
    }
    else
    {
        foreach (T item in source)
        {
            destination.Add(item);
        }
    }
}

This strategy uses type casting and conditional branching to exploit the performance benefits of List<T>.AddRange when possible, as it typically pre-allocates sufficient capacity before adding elements, reducing the overhead of multiple resizing operations. For non-List<T> collections, it falls back to the basic loop method. This balances generality and performance but adds complexity to the code.

Modern C# Feature Application

With the evolution of the .NET framework, C# has introduced more convenient features. For example, in .NET 4.5 and later versions, the ForEach method can be used as an alternative to foreach loops. Here is an example using ForEach:

source.ForEach(destination.Add);

This method is syntactically more concise and essentially equivalent to a foreach loop, serving as syntactic sugar. However, note that the ForEach method returns void, so it cannot be used for chaining or assignment operations. Additionally, developers should use such methods cautiously to avoid compromising code readability. From a performance standpoint, it is comparable to the basic loop method but may offer better expressiveness in certain scenarios.

Conclusion and Best Practices

In summary, implementing an AddRange extension method for ICollection<T> is a reasonable and practical technical solution. The basic implementation using a foreach loop is simple and general, suitable for most scenarios. If performance is a critical factor, especially when handling large collections, optimization strategies such as leveraging List<T>-specific methods can be considered. In modern C# development, features like ForEach can be incorporated to simplify code, but their limitations and applicability must be noted. In practice, developers should choose the most appropriate implementation based on specific needs, ensuring code that is both elegant and efficient.

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.