ความแตกต่างระหว่างArrayListและList<>ใน C # คืออะไร?
มันเป็นเพียงที่List<>มีประเภทในขณะที่ArrayListไม่ได้?
List<>โดยทั่วไปแล้วสิ่งนี้ถามเกี่ยวกับในขณะที่หนึ่งถามเกี่ยวกับList<object>เฉพาะ
ความแตกต่างระหว่างArrayListและList<>ใน C # คืออะไร?
มันเป็นเพียงที่List<>มีประเภทในขณะที่ArrayListไม่ได้?
List<>โดยทั่วไปแล้วสิ่งนี้ถามเกี่ยวกับในขณะที่หนึ่งถามเกี่ยวกับList<object>เฉพาะ
คำตอบ:
ใช่สวยมาก List<T>เป็นคลาสทั่วไป สนับสนุนการจัดเก็บค่าประเภทเฉพาะโดยไม่ต้องร่ายไปยังหรือจากobject(ซึ่งจะมีค่าใช้จ่ายที่เกิดขึ้นชกมวย / unboxing เมื่อTเป็นประเภทค่าในArrayListกรณี) ArrayListเพียงเก็บobjectการอ้างอิง เป็นคอลเล็กชันทั่วไปList<T>ใช้IEnumerable<T>อินเตอร์เฟสทั่วไปและสามารถใช้งานได้ง่ายใน LINQ (โดยไม่จำเป็นต้องมีCastหรือOfTypeเรียก)
ArrayListเป็นของวันที่ C # ไม่มีข้อมูลทั่วไป List<T>มันเลิกในความโปรดปรานของ คุณไม่ควรใช้ArrayListรหัสใหม่ที่กำหนดเป้าหมาย. NET> = 2.0 เว้นแต่ว่าคุณจะต้องเชื่อมต่อกับ API เก่าที่ใช้งาน
ArrayListat runtime ArrayListแบบคงที่แม้ว่ามันจะต้องหล่อด้วย
การใช้List<T>คุณสามารถป้องกันข้อผิดพลาดในการส่ง มันจะมีประโยชน์มากในการหลีกเลี่ยงการรันไทม์ข้อผิดพลาดหล่อ
ตัวอย่าง:
ที่นี่ (โดยใช้ArrayList) คุณสามารถรวบรวมรหัสนี้ แต่คุณจะเห็นข้อผิดพลาดในการดำเนินการในภายหลัง
ArrayList array1 = new ArrayList();
array1.Add(1);
array1.Add("Pony"); //No error at compile process
int total = 0;
foreach (int num in array1)
{
total += num; //-->Runtime Error
}
หากคุณใช้Listคุณหลีกเลี่ยงข้อผิดพลาดเหล่านี้:
List<int> list1 = new List<int>();
list1.Add(1);
//list1.Add("Pony"); //<-- Error at compile process
int total = 0;
foreach (int num in list1 )
{
total += num;
}
อ้างอิง: MSDN
เพื่อเพิ่มไปยังจุดดังกล่าว การใช้ArrayListในระบบปฏิบัติการ 64 บิตจะใช้หน่วยความจำ 2 เท่าเมื่อเทียบกับระบบปฏิบัติการ 32 บิต ในขณะเดียวกันรายการทั่วไปจะใช้หน่วยความจำต่ำกว่าList<T>ArrayList
ตัวอย่างเช่นหากเราใช้ขนาดArrayList19MB ใน 32 บิตจะใช้เวลา 39MB ใน 64 บิต แต่ถ้าคุณมีรายการทั่วไปList<int>8MB ใน 32 บิตมันจะใช้เวลาเพียง 8.1MB ใน 64 บิตซึ่งเป็นความแตกต่างไอกรน 481% เมื่อเทียบกับ ArrayList
ที่มา: รายการArrayList กับรายการทั่วไปสำหรับประเภทดั้งเดิมและ 64 บิต
ความแตกต่างอีกประการที่จะเพิ่มคือเกี่ยวกับการซิงโครไนซ์เธรด
ArrayListจัดเตรียมความปลอดภัยของเธรดบางส่วนผ่านคุณสมบัติการซิงโครไนซ์ซึ่งจะส่งคืน wrapper ที่ปลอดภัยสำหรับรอบคอลเลกชัน เสื้อคลุมทำงานโดยการล็อคคอลเลกชันทั้งหมดในทุกการดำเนินการเพิ่มหรือลบ ดังนั้นแต่ละเธรดที่พยายามเข้าถึงคอลเลกชันจะต้องรอการเลี้ยวเพื่อล็อคหนึ่งครั้ง สิ่งนี้ไม่สามารถปรับขนาดได้และอาจทำให้ประสิทธิภาพลดลงอย่างมากสำหรับคอลเลกชันขนาดใหญ่
List<T>ไม่มีการซิงโครไนซ์เธรดใด ๆ รหัสผู้ใช้จะต้องระบุการซิงโครไนซ์ทั้งหมดเมื่อมีการเพิ่มหรือลบรายการในหลายเธรดพร้อมกัน
ข้อมูลเพิ่มเติมที่นี่ Thread Synchronization ใน. Net Framework
ArrayListถ้ามันสามารถหลีกเลี่ยงได้ แต่นี่เป็นเหตุผลที่โง่ เสื้อคลุมเป็นตัวเลือกทั้งหมดหลังจากทั้งหมด; ถ้าคุณไม่ต้องการล็อคหรือถ้าคุณต้องการการควบคุมที่ละเอียดยิ่งขึ้นอย่าใช้กระดาษห่อ
คำตอบง่ายๆคือ
ArrayList arrayList = new ArrayList();
List<int> list = new List<int>();
arrayList.Add(1);
arrayList.Add("String");
arrayList.Add(new object());
list.Add(1);
list.Add("String"); // Compile-time Error
list.Add(new object()); // Compile-time Error
โปรดอ่านเอกสารอย่างเป็นทางการของ Microsoft : https://blogs.msdn.microsoft.com/kcwalina/2005/09/23/system-collections-vs-system-collection-generic-and-system-collections-objectmodel/
หมายเหตุ : คุณควรรู้ Generics ก่อนที่จะเข้าใจความแตกต่าง: https://docs.microsoft.com/en-us/dotnet/csharp/programming-guide/generics/
ArrayListคือการรวบรวมข้อมูลประเภทต่าง ๆ ในขณะที่List<>การเก็บรวบรวมประเภทที่คล้ายกันของ depedencties ของตัวเอง
ArrayListไม่ปลอดภัยขณะList<T>พิมพ์ปลอดภัย ง่าย :)
ผลงานของผู้ได้รับการกล่าวถึงอยู่แล้วในหลายคำตอบเป็นปัจจัยที่แตกต่าง แต่ยังที่อยู่ที่“ วิธีช้ามากคือArrayList? "และ" ทำไมจึงช้ากว่าโดยรวม?” ดูด้านล่าง
ArrayListเมื่อใดก็ตามที่ค่าชนิดที่ใช้เป็นองค์ประกอบประสิทธิภาพการทำงานลดลงอย่างมากกับการ พิจารณากรณีของการเพิ่มองค์ประกอบ เนื่องจากการชกมวยดำเนินต่อไปตามการArrayListเพิ่มจะใช้objectพารามิเตอร์เท่านั้นGarbage Collector จึงได้รับการกระตุ้นให้ทำงานได้ดีกว่าList<T>มาก
ความแตกต่างของเวลาเท่าไหร่ List<T>อย่างน้อยหลายครั้งช้ากว่าด้วย เพียงแค่ดูว่าเกิดอะไรขึ้นกับโค้ดที่เพิ่มค่า int 10 ล้านค่ากับArrayListvs List<T>:

นั่นคือความแตกต่างของเวลารันที่5xในคอลัมน์ 'Mean' ซึ่งเน้นเป็นสีเหลือง โปรดสังเกตความแตกต่างในจำนวนของการรวบรวมขยะที่ทำสำหรับแต่ละรายการเน้นด้วยสีแดง (ไม่มีการเรียกใช้ GCs / 1000)
การใช้ผู้สร้างโปรไฟล์เพื่อดูว่าเกิดอะไรขึ้นอย่างรวดเร็วแสดงให้เห็นว่าเวลาส่วนใหญ่ที่ใช้ในการทำ GCsตรงข้ามกับการเพิ่มองค์ประกอบจริง แถบสีน้ำตาลด้านล่างแสดงถึงการบล็อกกิจกรรม Garbage Collector:

ผมเคยเขียนวิเคราะห์รายละเอียดของสิ่งที่เกิดขึ้นกับข้างต้นArrayListสถานการณ์ที่นี่https://mihai-albert.com/2019/12/15/boxing-performance-in-c-analysis-and-benchmark/
การค้นพบที่คล้ายกันอยู่ใน“ CLR ผ่าน C #” โดย Jeffrey Richter จากบทที่ 12 (Generics):
[…] เมื่อฉันคอมไพล์และรัน build build (โดยเปิดใช้การออปติไมซ์) ของโปรแกรมนี้บนคอมพิวเตอร์ของฉันฉันจะได้ผลลัพธ์ต่อไปนี้
00: 00: 01.6246959 (GCs = 6) รายการ <Int32>
00: 00: 10.8555008 (GCs = 390)
Array รายการของ Int32 00: 00: 02.5427847 (GCs = 4) รายการ <String>
00: 00.7.7484831 (GCs = 7) ) ArrayList ของ Stringผลลัพธ์ที่นี่แสดงให้เห็นว่าการใช้อัลกอริทึมรายการปกติที่มีประเภท Int32 นั้นเร็วกว่าการใช้อัลกอริทึม ArrayList ที่ไม่ใช่แบบทั่วไปกับ Int32 ในความเป็นจริงความแตกต่างคือปรากฎการณ์: 1.6 วินาทีเทียบกับเกือบ 11 วินาที เร็วกว่า ~ 7 เท่า ! นอกจากนี้การใช้ประเภทค่า (Int32) กับ ArrayList ทำให้การดำเนินการชกมวยเกิดขึ้นมากมายซึ่งส่งผลให้มีการรวบรวมขยะ 390 ชุด ในขณะเดียวกันอัลกอริทึมรายการต้องการคอลเลกชันขยะ 6 รายการ
ฉันคิดว่าความแตกต่างระหว่างArrayListและList<T>คือ:
List<T>ที่ T ArrayListคือค่าชนิดจะเร็วกว่า นี่เป็นเพราะList<T>หลีกเลี่ยงการชกมวย / ไม่ทำกล่อง (โดยที่ T คือประเภทของค่า)ArrayListใช้เพื่อความเข้ากันได้ย้อนหลัง (ไม่ใช่ความแตกต่างที่แท้จริง แต่ฉันคิดว่ามันเป็นบันทึกที่สำคัญ)ArrayListแล้วList<T>ArrayListมีIsSynchronizedคุณสมบัติ ดังนั้นมันเป็นเรื่องง่ายที่จะสร้างและใช้ ArrayListsyncronised ฉัน didin't พบคุณสมบัติสำหรับIsSynchronized List<T>โปรดทราบว่าการซิงโครไนซ์ประเภทนี้ค่อนข้างไม่มีประสิทธิภาพmsdn ):
var arraylist = new ArrayList();
var arrayListSyncronized = ArrayList.Synchronized(arraylist
Console.WriteLine($"syncronized {arraylist.IsSynchronized}");
Console.WriteLine($"syncronized {arrayListSyncronized.IsSynchronized}");
var list = new List<object>();
var listSyncronized = ArrayList.Synchronized(list);
Console.WriteLine($"syncronized {list.IsSynchronized}");//error, no such prop
Console.WriteLine($"syncronized {list.IsSynchronized}");//error, no such propArrayListมีArrayList.SyncRootคุณสมบัติที่สามารถใช้สำหรับ syncronisation ( msdn ) List<T>ยังไม่มีSyncRootคุณสมบัติดังนั้นในการก่อสร้างต่อไปนี้คุณจำเป็นต้องใช้วัตถุบางอย่างถ้าคุณใช้List<T>:
ArrayList myCollection = new ArrayList();
lock(myCollection.SyncRoot) // ofcourse you can use another object for this goal
{
foreach (object item in myCollection)
{
// ...
}
}ดังกล่าวในเอกสาร . NET Framework
เราไม่แนะนำให้คุณใช้
ArrayListคลาสสำหรับการพัฒนาใหม่ เราขอแนะนำให้คุณใช้List<T>คลาสทั่วไปแทนArrayListชั้นถูกออกแบบมาเพื่อถือคอลเลกชันที่แตกต่างกันของวัตถุ อย่างไรก็ตามมันไม่ได้ให้ประสิทธิภาพที่ดีที่สุดเสมอไป เราขอแนะนำสิ่งต่อไปนี้แทน:
- สำหรับคอลเลกชันของวัตถุที่ต่างกันใช้ชนิด
List<Object>(ใน C #) หรือList(Of Object)(ใน Visual Basic) ชนิด- สำหรับชุดของวัตถุที่เป็นเนื้อเดียวกันให้ใช้
List<T>คลาส
การใช้ "รายการ" คุณสามารถป้องกันข้อผิดพลาดในการส่ง มันมีประโยชน์มากในการหลีกเลี่ยงข้อผิดพลาดในการส่งนักแปล
ตัวอย่าง:
ที่นี่ (โดยใช้ ArrayList) คุณสามารถรวบรวมรหัสนี้ แต่คุณจะเห็นข้อผิดพลาดในการดำเนินการในภายหลัง
// Create a new ArrayList
System.Collections.ArrayList mixedList = new System.Collections.ArrayList();
// Add some numbers to the list
mixedList.Add(7);
mixedList.Add(21);
// Add some strings to the list
mixedList.Add("Hello");
mixedList.Add("This is going to be a problem");
System.Collections.ArrayList intList = new System.Collections.ArrayList();
System.Collections.ArrayList strList = new System.Collections.ArrayList();
foreach (object obj in mixedList)
{
if (obj.GetType().Equals(typeof(int)))
{
intList.Add(obj);
}
else if (obj.GetType().Equals(typeof(string)))
{
strList.Add(obj);
}
else
{
// error.
}
}
สำหรับฉันมันคือทั้งหมดที่รู้เกี่ยวกับข้อมูลของคุณ หากฉันยังคงขยายโค้ดของฉันอย่างต่อเนื่องบนพื้นฐานของประสิทธิภาพฉันจะต้องเลือกตัวเลือกรายการเพื่อถอดรหัสข้อมูลของฉันโดยไม่มีขั้นตอนที่ไม่จำเป็นที่จะสงสัยเกี่ยวกับประเภทเสมอโดยเฉพาะ 'ประเภทที่กำหนดเอง' หากเครื่องเข้าใจถึงความแตกต่างและสามารถระบุได้ว่าเป็นข้อมูลประเภทใดที่ฉันกำลังเผชิญอยู่จริง ๆ แล้วทำไมฉันถึงต้องเสียเวลาและเสียเวลาไปกับการคำนวณของ 'IF THEN ELSE' ปรัชญาของฉันคือให้เครื่องทำงานแทนฉันแทนที่จะทำงานบนเครื่อง การทราบถึงความแตกต่างที่ไม่เหมือนใครของคำสั่งรหัสวัตถุที่แตกต่างนั้นทำให้การใช้รหัสของคุณมีประสิทธิภาพ
Tom Johnson (One Entry ... One Exit)