ความแตกต่างระหว่าง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 เก่าที่ใช้งาน
ArrayList
at 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
ตัวอย่างเช่นหากเราใช้ขนาดArrayList
19MB ใน 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 ล้านค่ากับArrayList
vs 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
คุณสมบัติ ดังนั้นมันเป็นเรื่องง่ายที่จะสร้างและใช้ ArrayList
syncronised ฉัน 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 prop
ArrayList
มี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)