ArrayList vs List <> ใน C #


412

ความแตกต่างระหว่างArrayListและList<>ใน C # คืออะไร?

มันเป็นเพียงที่List<>มีประเภทในขณะที่ArrayListไม่ได้?


5
สำเนาที่เป็นไปได้ของArrayList vs List <object>
John Saunders

5
มันเป็นคำถามที่ปิด แต่ฉันคิดว่าไม่ซ้ำกันอย่างแน่นอน List<>โดยทั่วไปแล้วสิ่งนี้ถามเกี่ยวกับในขณะที่หนึ่งถามเกี่ยวกับList<object>เฉพาะ
goodeye

พบบล็อกที่มีประโยชน์มากนี้อาจช่วยได้ คิดว่าฉันควรแชร์ลิงก์: fintechexplained.blogspot.co.uk/2017/07/ …
InfoLearner

คำตอบ:


533

ใช่สวยมาก List<T>เป็นคลาสทั่วไป สนับสนุนการจัดเก็บค่าประเภทเฉพาะโดยไม่ต้องร่ายไปยังหรือจากobject(ซึ่งจะมีค่าใช้จ่ายที่เกิดขึ้นชกมวย / unboxing เมื่อTเป็นประเภทค่าในArrayListกรณี) ArrayListเพียงเก็บobjectการอ้างอิง เป็นคอลเล็กชันทั่วไปList<T>ใช้IEnumerable<T>อินเตอร์เฟสทั่วไปและสามารถใช้งานได้ง่ายใน LINQ (โดยไม่จำเป็นต้องมีCastหรือOfTypeเรียก)

ArrayListเป็นของวันที่ C # ไม่มีข้อมูลทั่วไป List<T>มันเลิกในความโปรดปรานของ คุณไม่ควรใช้ArrayListรหัสใหม่ที่กำหนดเป้าหมาย. NET> = 2.0 เว้นแต่ว่าคุณจะต้องเชื่อมต่อกับ API เก่าที่ใช้งาน


คุณจะอธิบายได้ไหมว่าทำไมคุณถึงใช้ "มวย" และไม่ใช่ "ชี้ขาด"? มวยเกิดอะไรขึ้นที่นี่? มีการจัดสรร / ยกเลิกการจัดสรรวัตถุหรือไม่
Benjamin Gruenbaum

2
@BenjaminGruenbaum คุณถูกต้องแล้วว่าการคัดเลือกนักแสดงจะเป็นเรื่องทั่วไปมากขึ้น ที่กล่าวไว้ว่าความแตกต่างที่แท้จริงของรันไทม์คือเมื่อคุณกำลังจัดการกับประเภทของค่า สำหรับประเภทการอ้างอิงพฤติกรรมจะมีประสิทธิภาพเหมือนกับArrayListat runtime ArrayListแบบคงที่แม้ว่ามันจะต้องหล่อด้วย
Mehrdad Afshari

ฉันสงสัยว่ากรอบงานควร จำกัด T ให้เป็นประเภท "วัตถุ" หรือไม่เพราะ ArrayList อนุญาตให้ทำเช่นนั้นได้
rajibdotnet

เกี่ยวกับการคัดค้านคอลเลกชันที่ไม่ได้พิมพ์โปรดดูทั่วไปที่พิจารณาว่าเป็นอันตราย
Ant_222

@ Ant_222 บล็อกนั้นเขียนเกือบ 15 ปีที่แล้ว ฉันคิดว่าหลักฐานในทศวรรษที่ผ่านมา + แสดงให้เห็นว่ายาชื่อสามัญไม่เป็นอันตราย :)
Scott Adams

101

การใช้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 เพื่อป้องกันข้อผิดพลาดในการส่ง ตอนนี้ผู้คนใช้วัตถุทำให้ ArrayList ไม่จำเป็นอีกต่อไป
สลับ

1
ฉัน +1 เพื่อเหตุผล แต่คุณยังสามารถทำได้หาก (จำนวน NUM เป็น int) {} ไปยังรายการอาร์เรย์ของคุณเพื่อหลีกเลี่ยงข้อผิดพลาด
Mina Gabriel

ป้องกันข้อผิดพลาดในการส่งและค่าใช้จ่ายในการชกมวย ค่อนข้างทั่วไปสำหรับเหตุผลทั่วไป
marsze

26

เพื่อเพิ่มไปยังจุดดังกล่าว การใช้ArrayListในระบบปฏิบัติการ 64 บิตจะใช้หน่วยความจำ 2 เท่าเมื่อเทียบกับระบบปฏิบัติการ 32 บิต ในขณะเดียวกันรายการทั่วไปจะใช้หน่วยความจำต่ำกว่าList<T>ArrayList

ตัวอย่างเช่นหากเราใช้ขนาดArrayList19MB ใน 32 บิตจะใช้เวลา 39MB ใน 64 บิต แต่ถ้าคุณมีรายการทั่วไปList<int>8MB ใน 32 บิตมันจะใช้เวลาเพียง 8.1MB ใน 64 บิตซึ่งเป็นความแตกต่างไอกรน 481% เมื่อเทียบกับ ArrayList

ที่มา: รายการArrayList กับรายการทั่วไปสำหรับประเภทดั้งเดิมและ 64 บิต


5
ซึ่งเป็นจริงสำหรับการจัดเก็บประเภทค่าไม่ใช่ประเภทการอ้างอิง ความแตกต่างนั้นเกิดจากความจริงที่ว่า arraylist สามารถมีพอยน์เตอร์ได้เท่านั้นและต้องมีการจัดเก็บข้อมูลเอง ในทางกลับกันประเภทค่าสามารถจัดเก็บโดยตรงในรายการ
Rasmus Damgaard Nielsen

19

ความแตกต่างอีกประการที่จะเพิ่มคือเกี่ยวกับการซิงโครไนซ์เธรด

ArrayListจัดเตรียมความปลอดภัยของเธรดบางส่วนผ่านคุณสมบัติการซิงโครไนซ์ซึ่งจะส่งคืน wrapper ที่ปลอดภัยสำหรับรอบคอลเลกชัน เสื้อคลุมทำงานโดยการล็อคคอลเลกชันทั้งหมดในทุกการดำเนินการเพิ่มหรือลบ ดังนั้นแต่ละเธรดที่พยายามเข้าถึงคอลเลกชันจะต้องรอการเลี้ยวเพื่อล็อคหนึ่งครั้ง สิ่งนี้ไม่สามารถปรับขนาดได้และอาจทำให้ประสิทธิภาพลดลงอย่างมากสำหรับคอลเลกชันขนาดใหญ่

List<T>ไม่มีการซิงโครไนซ์เธรดใด ๆ รหัสผู้ใช้จะต้องระบุการซิงโครไนซ์ทั้งหมดเมื่อมีการเพิ่มหรือลบรายการในหลายเธรดพร้อมกัน

ข้อมูลเพิ่มเติมที่นี่ Thread Synchronization ใน. Net Framework


ฉันไม่ได้บอกว่าคุณควรใช้ArrayListถ้ามันสามารถหลีกเลี่ยงได้ แต่นี่เป็นเหตุผลที่โง่ เสื้อคลุมเป็นตัวเลือกทั้งหมดหลังจากทั้งหมด; ถ้าคุณไม่ต้องการล็อคหรือถ้าคุณต้องการการควบคุมที่ละเอียดยิ่งขึ้นอย่าใช้กระดาษห่อ
Thorarin

1
หากคุณต้องการความปลอดภัยของด้ายฉันขอแนะนำให้ดูที่ System.Collections.Concurrent เนมสเปซก่อนพิจารณา ArrayList
Ykok

15

คำตอบง่ายๆคือ

ArrayList ไม่ใช่แบบทั่วไป

  • มันเป็นประเภทวัตถุดังนั้นคุณสามารถจัดเก็บประเภทข้อมูลใด ๆ ลงไปได้
  • คุณสามารถเก็บค่าใด ๆ (ประเภทค่าหรือประเภทอ้างอิง) เช่นสตริง, int, พนักงานและวัตถุใน ArrayList (หมายเหตุและ)
  • มวยและ Unboxing จะเกิดขึ้น
  • ไม่พิมพ์ปลอดภัย
  • มันมีอายุมากกว่า

รายการคือ Generic

  • มันเป็นประเภทของประเภทดังนั้นคุณสามารถระบุ T ในเวลาทำงาน
  • คุณสามารถเก็บค่าประเภท T (สตริงหรือ int หรือพนักงานหรือวัตถุ) เท่านั้นตามการประกาศ (หมายเหตุหรือ)
  • Boxing และ Unboxing จะไม่เกิดขึ้น
  • พิมพ์ปลอดภัย
  • มันใหม่กว่า

ตัวอย่าง:

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/




2

ผลงานของผู้ได้รับการกล่าวถึงอยู่แล้วในหลายคำตอบเป็นปัจจัยที่แตกต่าง แต่ยังที่อยู่ที่“ วิธีช้ามากคือ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 รายการ


1

ฉันคิดว่าความแตกต่างระหว่างArrayListและList<T>คือ:

  1. List<T>ที่ T ArrayListคือค่าชนิดจะเร็วกว่า นี่เป็นเพราะList<T>หลีกเลี่ยงการชกมวย / ไม่ทำกล่อง (โดยที่ T คือประเภทของค่า)
  2. หลายแหล่งกล่าวว่า - มักArrayListใช้เพื่อความเข้ากันได้ย้อนหลัง (ไม่ใช่ความแตกต่างที่แท้จริง แต่ฉันคิดว่ามันเป็นบันทึกที่สำคัญ)
  3. สะท้อนเป็นง่ายขึ้นด้วย nongeneric ArrayListแล้วList<T>
  4. 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 prop
  5. 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)
        {
            // ...
        }
    }

0

ดังกล่าวในเอกสาร . NET Framework

เราไม่แนะนำให้คุณใช้ArrayListคลาสสำหรับการพัฒนาใหม่ เราขอแนะนำให้คุณใช้List<T> คลาสทั่วไปแทน ArrayListชั้นถูกออกแบบมาเพื่อถือคอลเลกชันที่แตกต่างกันของวัตถุ อย่างไรก็ตามมันไม่ได้ให้ประสิทธิภาพที่ดีที่สุดเสมอไป เราขอแนะนำสิ่งต่อไปนี้แทน:

  • สำหรับคอลเลกชันของวัตถุที่ต่างกันใช้ชนิดList<Object>(ใน C #) หรือList(Of Object)(ใน Visual Basic) ชนิด
  • สำหรับชุดของวัตถุที่เป็นเนื้อเดียวกันให้ใช้List<T>คลาส

ดูคอลเลกชันที่ไม่ใช่ทั่วไปไม่ควรใช้

ตารางแสดงวิธีที่ประเภทคอลเลกชันที่ไม่ใช่ทั่วไปสามารถถูกแทนที่ด้วยคู่ทั่วไปของพวกเขา


-2

การใช้ "รายการ" คุณสามารถป้องกันข้อผิดพลาดในการส่ง มันมีประโยชน์มากในการหลีกเลี่ยงข้อผิดพลาดในการส่งนักแปล

ตัวอย่าง:

ที่นี่ (โดยใช้ 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.
        }
    }

สิ่งนี้เพิ่มอะไรนอกเหนือจากคำตอบที่ให้ไว้เมื่อสามปีก่อน? มันมีเกือบทุกคำต่อคำข้อความโดยไม่ต้องเชื่อมโยงไปยังแหล่งที่มาโดยไม่ต้องจัดรูปแบบได้อย่างถูกต้องและอื่น ๆ
Douglas Zare

-3

สำหรับฉันมันคือทั้งหมดที่รู้เกี่ยวกับข้อมูลของคุณ หากฉันยังคงขยายโค้ดของฉันอย่างต่อเนื่องบนพื้นฐานของประสิทธิภาพฉันจะต้องเลือกตัวเลือกรายการเพื่อถอดรหัสข้อมูลของฉันโดยไม่มีขั้นตอนที่ไม่จำเป็นที่จะสงสัยเกี่ยวกับประเภทเสมอโดยเฉพาะ 'ประเภทที่กำหนดเอง' หากเครื่องเข้าใจถึงความแตกต่างและสามารถระบุได้ว่าเป็นข้อมูลประเภทใดที่ฉันกำลังเผชิญอยู่จริง ๆ แล้วทำไมฉันถึงต้องเสียเวลาและเสียเวลาไปกับการคำนวณของ 'IF THEN ELSE' ปรัชญาของฉันคือให้เครื่องทำงานแทนฉันแทนที่จะทำงานบนเครื่อง การทราบถึงความแตกต่างที่ไม่เหมือนใครของคำสั่งรหัสวัตถุที่แตกต่างนั้นทำให้การใช้รหัสของคุณมีประสิทธิภาพ

Tom Johnson (One Entry ... One Exit)

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.