วิธีการคัดลอก List<T> ใน C# โดยไม่ต้องใช้ foreach
List<T> เป็นคอลเลกชันเจเนอริกที่เข้าถึงด้วยดัชนีได้ มีเมธอดสำหรับจัดเรียง ค้นหา และแก้ไข อยู่ในเนมสเปซ System.Collections.Generic
วิธีที่ 1: Constructor คัดลอก (Copy Constructor) - แนะนำมากที่สุด
using System;
using System.Collections.Generic;
class Program
{
public static void Main()
{
List<int> originalList = new List<int> { 1, 2, 3, 4, 5, 7, 8, 9 };
// สร้าง List ใหม่โดยส่ง original เข้า constructor
List<int> copy = new List<int>(originalList);
// ตรวจสอบว่าเป็นคนละ object (Shallow Copy)
Console.WriteLine($"Same reference? {object.ReferenceEquals(originalList, copy)}"); // False
Console.WriteLine($"Same contents? {originalList.SequenceEqual(copy)}"); // True
// แก้ไข copy ไม่กระทบ original
copy.Add(99);
Console.WriteLine($"Original count: {originalList.Count}"); // 8
Console.WriteLine($"Copy count: {copy.Count}"); // 9
}
}
วิธีที่ 2: ToList() (LINQ)
using System;
using System.Collections.Generic;
using System.Linq;
class Program
{
public static void Main()
{
List<int> originalList = new List<int> { 1, 2, 3, 4, 5, 7, 8, 9 };
// ใช้ LINQ ToList()
List<int> copy = originalList.ToList();
// เหมือน Constructor แต่อ่านง่ายกว่าในบางบริบท
copy.Add(99);
Console.WriteLine($"Original: {originalList.Count}, Copy: {copy.Count}");
}
}
วิธีที่ 3: GetRange() - คัดลอกบางส่วน
using System;
using System.Collections.Generic;
class Program
{
public static void Main()
{
List<int> originalList = new List<int> { 1, 2, 3, 4, 5, 7, 8, 9 };
// คัดลอก 3 ตัวแรก (index 0, จำนวน 3)
List<int> partialCopy = originalList.GetRange(0, 3);
Console.WriteLine("Partial copy: " + string.Join(", ", partialCopy)); // 1, 2, 3
// คัดลอกตั้งแต่ index 3 จนจบ
List<int> fromIndex3 = originalList.GetRange(3, originalList.Count - 3);
Console.WriteLine("From index 3: " + string.Join(", ", fromIndex3)); // 4, 5, 7, 8, 9
}
}
วิธีที่ 4: เพิ่มทีหลังด้วย AddRange()
using System;
using System.Collections.Generic;
class Program
{
public static void Main()
{
List<int> originalList = new List<int> { 1, 2, 3 };
List<int> copy = new List<int>(); // ว่าง
copy.AddRange(originalList); // เพิ่มทีหลัง
// หรือกำหนด Capacity ล่วงหน้าเพื่อประสิทธิภาพ
List<int> copy2 = new List<int>(originalList.Count);
copy2.AddRange(originalList);
}
}
วิธีที่ 5: Collection Initializer (C# 3.0+)
using System;
using System.Collections.Generic;
class Program
{
public static void Main()
{
List<int> originalList = new List<int> { 1, 2, 3 };
// Spread operator ไม่มีใน C# ต้องทำแบบนี้
List<int> copy = new List<int>(originalList); // วิธีสั้นที่สุด
// หรือถ้าต้องการเพิ่มค่าอื่นพร้อมกัน
List<int> extended = new List<int>(originalList) { 4, 5, 6 };
// ผลลัพธ์: 1, 2, 3, 4, 5, 6
}
}
ตารางเปรียบเทียบ
| วิธี | Syntax | คัดลอกบางส่วนได้? | ประสิทธิภาพ | ความชัดเจน |
|---|---|---|---|---|
| Constructor | new List<T>(original) | ไม่ได้ (ต้องใช้ GetRange) | ดีมาก | ชัดเจนมาก |
| ToList() | original.ToList() | ไม่ได้ | ดี | อ่านง่าย (LINQ style) |
| GetRange | original.GetRange(index, count) | ได้ | ดี | ชัดเจนสำหรับ subset |
| AddRange | copy.AddRange(original) | ได้ (รวมกับ list เดิม) | ดี | เหมาะสำหรับ merge |
Shallow Copy vs Deep Copy
ทุกวิธีข้างต้นเป็น Shallow Copy - คัดลอก reference ของ object ไป (ถ้า T เป็น reference type)
class Person { public string Name; }
var original = new List<Person> { new Person { Name = "A" } };
var copy = new List<Person>(original); // Shallow copy
copy[0].Name = "B";
Console.WriteLine(original[0].Name); // "B" - เปลี่ยนไปด้วย!
Deep Copy (ถ้าจำเป็น)
// 1. Manual copy
var deepCopy = original.Select(p => new Person { Name = p.Name }).ToList();
// 2. JSON serialize/deserialize (ง่ายแต่ช้า)
var json = JsonConvert.SerializeObject(original);
var deepCopy2 = JsonConvert.DeserializeObject<List<Person>>(json);
// 3. ICloneable interface (ต้อง implement เอง)
สรุปแนะนำ
- คัดลอกทั้ง List: ใช้
new List<T>(original)- เร็วที่สุด อ่านง่าย - คัดลอกบางส่วน: ใช้
original.GetRange(start, count) - รวม List: ใช้
list1.AddRange(list2)หรือlist1.Concat(list2).ToList() - Deep copy: ต้องเขียนเองหรือใช้ Serialization