Deep Copying List<T> in C#: A Technical Guide

Dec 01, 2025 · Programming · 10 views · 7.8

Keywords: c# | list | clone | deep-copy

Abstract: This article explains how to perform a deep copy of a List<T> in C#, covering methods like LINQ Select and ConvertAll, and introducing the ICloneable interface for object cloning. Aimed at developers seeking to avoid reference sharing issues in collections, with detailed analysis based on sample code and best practice recommendations.

Understanding Shallow vs Deep Copy in C# Lists

In C#, the List<T> class provides a constructor that accepts an IEnumerable<T> to create a new list, but this results in a shallow copy. A shallow copy means the list itself is a new object, but the elements within it are references to the original objects. Modifying the copied list can inadvertently change the original elements, potentially causing bugs.

Deep Copy Solution Using LINQ

To achieve a deep copy, where both the list and its elements are independent, you can use LINQ's Select method combined with ToList. This approach creates new instances of the objects to avoid reference sharing.

List<Book> books_2 = books_1.Select(book => new Book(book.title)).ToList();

This code iterates over each Book in books_1, creates a new Book with the same title, and collects them into a new list. As a result, books_2 and books_1 will not affect each other.

Alternative Method: Using ConvertAll

Another efficient way is to use the ConvertAll method of List<T>, which returns a new list after applying a converter function.

List<Book> books_2 = books_1.ConvertAll(book => new Book(book.title));

ConvertAll is similar to Select but is specific to lists and may offer better performance in some cases.

Extending with ICloneable Interface

For more complex classes, implementing a cloning interface can enhance flexibility. Inspired by other answers, you can define a generic ICloneable<T> interface.

public interface ICloneable<T>
{
    T Clone();
}

public class Book : ICloneable<Book>
{
    public string Title { get; set; }

    public Book Clone()
    {
        return new Book { Title = this.Title };
    }
}

Then, you can clone the list as follows:

List<Book> books_2 = books_1.Select(book => book.Clone()).ToList();

Practical Example Based on Provided Code

Using the original code snippet, here's how to modify it for deep copy:

using System;
using System.Collections.Generic;
using System.Linq;

namespace clone_test_01
{
    public class Book
    {
        public string Title { get; set; }

        public Book(string title)
        {
            this.Title = title;
        }
    }

    public partial class MainForm : Form
    {
        public MainForm()
        {
            InitializeComponent();

            List<Book> books_1 = new List<Book>();
            books_1.Add(new Book("One"));
            books_1.Add(new Book("Two"));
            books_1.Add(new Book("Three"));
            books_1.Add(new Book("Four"));

            // Deep copy using LINQ
            List<Book> books_2 = books_1.Select(book => new Book(book.Title)).ToList();

            // Modifications to books_2 will not affect books_1
            books_2[0].Title = "Five";
            books_2[1].Title = "Six";

            textBox1.Text = books_1[0].Title; // Still "One"
            textBox2.Text = books_1[1].Title; // Still "Two"
        }
    }
}

Conclusion

Creating a deep copy of a List<T> in C# requires manual instantiation of new objects. The Select with ToList and ConvertAll methods are straightforward solutions. For scalable applications, implementing a cloning interface like ICloneable<T> can improve maintainability. Always consider the complexity of the objects when choosing a cloning strategy.

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.