C# - 리스트 복사 (얕은 복사, 깊은 복사)

먼저 얕은 복사로 리스트를 복사하는 방법을 설명합니다. 그리고 얕은 복사로 문제가 발생할 수 있는 상황과 깊은 복사로 해결하는 방법에 대해서 알아보겠습니다.

1. 리스트 복사 (얕은 복사)

얕은 복사로 리스트를 복사하는 방법을 소개합니다.

1.1 List 생성자를 이용한 방법

아래 예제와 같이 new List<string>(list)으로 리스트를 생성할 때 인자로 리스트를 전달하여 복사할 수 있습니다.

using System;

namespace Example {

    public class Program {

        public static void Main(string[] args) {

            List<string> list = new List<string>() {"a", "b", "c", "d"};

            List<string> copy = new List<string>(list);

            Console.WriteLine(string.Join(", ", list));
            Console.WriteLine(string.Join(", ", copy));
        }
    }
}

Output:

a, b, c, d
a, b, c, d

1.2 List.ToList()를 이용한 방법

list.ToList()는 복사된 리스트를 리턴합니다.

List<string> list = new List<string>() {"a", "b", "c", "d"};

List<string> copy = list.ToList();

Console.WriteLine(string.Join(", ", list));
Console.WriteLine(string.Join(", ", copy));

Output:

a, b, c, d
a, b, c, d

1.3 List.GetRange()를 이용한 방법

list.GetRange(index, count)는 리스트의 index에서 count 개수만큼의 요소를 새로운 리스트에 추가하여 리턴합니다.

아래와 같이 GetRange()로 리스트를 복사할 수 있습니다.

List<string> list = new List<string>() {"a", "b", "c", "d"};

List<string> copy = list.GetRange(0, list.Count);

Console.WriteLine(string.Join(", ", list));
Console.WriteLine(string.Join(", ", copy));

Output:

a, b, c, d
a, b, c, d

2. 얕은 복사로 발생하는 문제

string, int 같은 기본 자료형이 아니고, 클래스 객체를 갖고 있는 리스트일 때 얕은 복사를 사용했을 때 문제가 될 수 있습니다.

예를 들어, 아래 예제는

  • Person 객체의 리스트를 얕은 복사로 복사합니다.
  • 복사된 리스트에서 Index 0Person 객체의 age를 0으로 변경합니다.
  • 원본 리스트와 복사된 리스트의 내용을 확인해보면, 둘다 Johnage가 0으로 변경되었습니다.

앝은 복사는 리스트가 객체 정보만 복사하여 참조하기 때문에, 객체 안의 데이터는 복사되지 않고 두개의 리스트가 함께 참조하게 됩니다. 이 데이터가 변경되면 원본 리스트와 복사본 리스트가 참조하는 객체 정보가 함께 변경됩니다.

using System;

namespace Example {
    public class Person {
        public string name;
        public int age;

        public Person(string name, int age) {
            this.name = name;
            this.age = age;
        }

        public override string ToString() {
            return "[" + name + ", " + age + "]";
        }
    }

    public class Program {

        public static void Main(string[] args) {

            List<Person> list = new List<Person>();
            list.Add(new Person("John", 30));
            list.Add(new Person("Patrick", 34));
            list.Add(new Person("Doe", 22));

            List<Person> copy = new List<Person>(list);
            copy.ElementAt(0).age = 0;

            Console.WriteLine(string.Join(", ", list));
            Console.WriteLine(string.Join(", ", copy));
        }
    }
}

Output:

[John, 0], [Patrick, 34], [Doe, 22]
[John, 0], [Patrick, 34], [Doe, 22]

3. 리스트 복사 (깊은 복사)

List.ConvertAll(converter)는 리스트의 요소를 converter를 사용하여 다른 데이터로 변경하는 함수입니다.

리스트의 모든 요소에 대해서 아래와 같이 Person 객체를 재생성하여 리턴하면, 객체 자체를 복사한 리스트가 생성됩니다.

  • ConvertAll(p => new Person(p.name, p.age))

객체 자체를 복사하였기 때문에, 원본 리스트와 복사된 리스트는 서로 다른 객체를 갖고 있으며, 아래와 같이 특정 요소의 값을 변경해도 다른 리스트에 영향을 주지 않게 됩니다.

using System;

namespace Example {
    public class Person {
        public string name;
        public int age;

        public Person(string name, int age) {
            this.name = name;
            this.age = age;
        }

        public override string ToString() {
            return "[" + name + ", " + age + "]";
        }
    }

    public class Program {

        public static void Main(string[] args) {

            List<Person> list = new List<Person>();
            list.Add(new Person("John", 30));
            list.Add(new Person("Patrick", 34));
            list.Add(new Person("Doe", 22));

            List<Person> copy = list.ConvertAll(
                    p => new Person(p.name, p.age));
            copy.ElementAt(0).age = 0;

            Console.WriteLine(string.Join(", ", list));
            Console.WriteLine(string.Join(", ", copy));
        }
    }
}

Output:

[John, 30], [Patrick, 34], [Doe, 22]
[John, 0], [Patrick, 34], [Doe, 22]
Loading script...
codechachaCopyright ©2019 codechacha