ArrayList vs List <> trong C #


412

Sự khác biệt giữa ArrayListList<>trong C # là gì?

Có phải chỉ List<>có một loại trong khi ArrayListkhông?


5
có thể trùng lặp ArrayList vs List <object>
John Saunders

5
Đó là một câu hỏi gần gũi, nhưng tôi nghĩ không chính xác trùng lặp. Điều này hỏi về List<>nói chung, trong khi người ta hỏi về List<object>cụ thể
goodeye

Tìm thấy blog này rất hữu ích, nó có thể giúp đỡ. Thiết nghĩ tôi nên chia sẻ liên kết: fintechexplained.blogspot.co.uk/2017/07/ Kẻ
InfoLearner

Câu trả lời:


533

Vâng, khá nhiều. List<T>là một lớp học chung. Nó hỗ trợ lưu trữ các giá trị của một loại cụ thể mà không cần truyền đến hoặc từ object(điều này sẽ phát sinh quyền anh / bỏ hộp khi Tcó loại giá trị trong ArrayListtrường hợp). ArrayListchỉ đơn giản là lưu trữ objecttài liệu tham khảo. Là một bộ sưu tập chung, List<T>thực hiện IEnumerable<T>giao diện chung và có thể được sử dụng dễ dàng trong LINQ (không yêu cầu bất kỳ Casthoặc OfTypecuộc gọi nào).

ArrayListthuộc về những ngày mà C # không có thuốc generic. Nó không được ủng hộ List<T>. Bạn không nên sử dụng ArrayListmã mới nhắm mục tiêu .NET> = 2.0 trừ khi bạn phải giao tiếp với API cũ sử dụng nó.


Bạn có phiền giải thích lý do tại sao bạn sử dụng "quyền anh" mà không "đúc" không? Quyền anh gì xảy ra ở đây? Là đối tượng được phân bổ / giải quyết?
Benjamin Gruenbaum

2
@BenjaminGruenbaum Bạn nói đúng rằng việc casting sẽ chung chung hơn. Điều đó nói rằng, sự khác biệt thực sự trong thời gian chạy là khi bạn xử lý các loại giá trị (đó là những gì tôi giả định khi tôi viết "quyền anh"). Đối với các loại tham chiếu, hành vi có hiệu quả tương tự như ArrayListtrong thời gian chạy. Mặc dù vậy, nó sẽ yêu cầu diễn viên ArrayList.
Mehrdad Afshari

Tôi đã tự hỏi liệu khung công tác có nên hạn chế T thuộc loại "đối tượng" hay không, vì ArrayList hoàn toàn cho phép điều đó.
rajibdotnet

Về sự phản đối của các bộ sưu tập chưa được chỉnh sửa, hãy xem Generics được coi là có hại
Ant_222

@ Ant_222, blog đó đã được viết cách đây gần 15 năm. Tôi nghĩ rằng bằng chứng trong thập kỷ qua + đã chỉ ra rằng thuốc generic không có hại. :)
Scott Adams

101

Sử dụng List<T>bạn có thể ngăn ngừa lỗi đúc. Nó rất hữu ích để tránh một lỗi đúc thời gian chạy .

Thí dụ:

Tại đây (sử dụng ArrayList) bạn có thể biên dịch mã này nhưng bạn sẽ thấy lỗi thực thi sau đó.

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
}

Nếu bạn sử dụng List, bạn tránh những lỗi này:

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;
}

Tham khảo: MSDN


Bạn có thể kiểm tra loại khi bạn kéo từ ArrayList để tránh lỗi truyền. Ngày nay mọi người sử dụng đối tượng, làm cho ArrayList không còn cần thiết nữa.
Chuyển

1
i +1 để biện minh nhưng bạn vẫn có thể làm nếu (num là int) {} vào danh sách mảng của bạn để tránh lỗi
Mina Gabriel

Ngăn ngừa lỗi đúc và đấm bốc trên đầu. Khá nhiều lý do cho thuốc generic nói chung.
soái ca

26

Để thêm vào các điểm trên. Sử dụng ArrayListtrong hệ điều hành 64 bit chiếm bộ nhớ gấp 2 lần so với sử dụng trong hệ điều hành 32 bit. Trong khi đó, danh sách chung List<T>sẽ sử dụng bộ nhớ thấp hơn nhiều so với ArrayList.

ví dụ: nếu chúng ta sử dụng ArrayList19 MB trong 32 bit thì sẽ mất 39 MB trong 64 bit. Nhưng nếu bạn có một danh sách chung List<int>8 MB trong 32 bit thì sẽ chỉ mất 8.1 MB trong 64 bit, đó là một sự khác biệt lớn hơn 480% khi so sánh với ArrayList.

Nguồn: Danh sách chung của ArrayList cho các kiểu nguyên thủy và 64 bit


5
Điều đó chỉ đúng khi lưu trữ các loại giá trị, không phải loại tham chiếu. sự khác biệt là do một danh sách mảng chỉ có thể chứa con trỏ và dữ liệu cần được lưu trữ ở nơi khác. Mặt khác, các loại giá trị có thể được lưu trữ trực tiếp trong một danh sách.
Rasmus Damgaard Nielsen

19

Một sự khác biệt khác để thêm là liên quan đến Đồng bộ hóa luồng.

ArrayListcung cấp một số an toàn luồng thông qua thuộc tính Đồng bộ hóa, trả về trình bao bọc an toàn luồng xung quanh bộ sưu tập. Trình bao bọc hoạt động bằng cách khóa toàn bộ bộ sưu tập trên mỗi thao tác thêm hoặc xóa. Do đó, mỗi luồng đang cố truy cập vào bộ sưu tập phải chờ đến lượt để lấy một khóa. Điều này không thể mở rộng và có thể gây suy giảm hiệu suất đáng kể cho các bộ sưu tập lớn.

List<T>không cung cấp bất kỳ đồng bộ hóa chủ đề; mã người dùng phải cung cấp tất cả đồng bộ hóa khi các mục được thêm hoặc xóa trên nhiều luồng đồng thời.

Thêm thông tin ở đây Đồng bộ hóa luồng trong .Net Framework


Tôi không nói bạn nên sử dụng ArrayListnếu có thể tránh được, nhưng đây là một lý do ngớ ngẩn. Rốt cuộc là hoàn toàn tùy chọn; nếu bạn không cần khóa hoặc nếu bạn cần kiểm soát chi tiết hơn, đừng sử dụng trình bao bọc.
Thorarin

1
Nếu bạn muốn an toàn luồng, tôi khuyên bạn nên xem xét không gian tên System.Collections.Conc hiện trước khi xem xét ArrayList.
Ykok

15

Câu trả lời đơn giản là

ArrayList là không chung

  • Nó là Loại đối tượng, vì vậy bạn có thể lưu trữ bất kỳ loại dữ liệu nào vào đó.
  • Bạn có thể lưu trữ bất kỳ giá trị nào (kiểu giá trị hoặc kiểu tham chiếu) như chuỗi, int, worker và object trong ArrayList. (Lưu ý và)
  • Quyền anh và Unboxing sẽ xảy ra.
  • Không loại an toàn.
  • Nó là cũ hơn.

Danh sách là Chung

  • Đó là Loại Loại, vì vậy bạn có thể chỉ định T theo thời gian chạy.
  • Bạn có thể lưu trữ một giá trị duy nhất của Loại T (chuỗi hoặc int hoặc nhân viên hoặc đối tượng) dựa trên khai báo. (Lưu ý hoặc)
  • Quyền anh và Unboxing sẽ không xảy ra.
  • Loại an toàn.
  • Nó là mới hơn.

Thí dụ:

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

Vui lòng đọc tài liệu chính thức của Microsoft : https://bloss.msdn.microsoft.com/kcwalina/2005/09/23/system-collections-vs-system-collection-generic-and-system-collections-objectmodel/

nhập mô tả hình ảnh ở đây

Lưu ý : Bạn nên biết Generics trước khi hiểu sự khác biệt: https://docs.microsoft.com/en-us/dotnet/csharp/programming-guide/generics/


4

ArrayListlà tập hợp của các loại dữ liệu khác nhau trong khi đó List<>là tập hợp các kiểu tương tự của chính nó.


3

ArrayListkhông phải là loại an toàn trong khi đó List<T>là loại an toàn. Đơn giản :).


2

Hiệu suất đã được đề cập trong một số câu trả lời như là một yếu tố khác biệt, nhưng để giải quyết vấn đề thì chậm hơn bao nhiêu ArrayList? ”Và“ Tại sao nó chậm hơn tổng thể?Mùi, có một cái nhìn dưới đây.

Bất cứ khi nào các loại giá trị được sử dụng làm yếu tố, hiệu suất giảm đáng kể với ArrayList. Hãy xem xét trường hợp chỉ cần thêm các yếu tố. Do quyền anh đang diễn ra - vì ArrayListThêm chỉ lấy objecttham số - Trình thu gom rác được kích hoạt để thực hiện nhiều công việc hơn so vớiList<T> .

Chênh lệch thời gian là bao nhiêu? Ít nhất vài lần chậm hơn so với với List<T>. Chỉ cần xem những gì xảy ra với mã thêm 10 triệu giá trị int vào ArrayListvs List<T>: nhập mô tả hình ảnh ở đây

Đó là sự khác biệt về thời gian chạy 5x trong cột 'Trung bình', được tô sáng màu vàng. Cũng lưu ý sự khác biệt về số lượng bộ sưu tập rác được thực hiện cho mỗi bộ, được tô sáng màu đỏ (không có GC / 1000 lần chạy).

Sử dụng một trình lược tả để xem những gì đang diễn ra nhanh chóng cho thấy rằng phần lớn thời gian được dành cho việc thực hiện các GC , trái ngược với việc thực sự thêm các yếu tố. Các thanh màu nâu bên dưới đại diện cho hoạt động chặn Rác Collector: nhập mô tả hình ảnh ở đây

Tôi đã viết một phân tích chi tiết về những gì diễn ra với ArrayListkịch bản trên đây https://mihai-albert.com/2019/12/15/boxing-performance-in-c-analysis-and-benchmark/ .

Những phát hiện tương tự cũng có trong CÂU LẠC qua C # Cảnh của Jeffrey Richter. Từ chương 12 (Generics):

[V]] Khi tôi biên dịch và chạy bản dựng phát hành (đã bật tối ưu hóa) chương trình này trên máy tính của mình, tôi nhận được kết quả đầu ra sau.

00: 00: 01.6246959 (GCs = 6) Danh sách <Int32>
00: 00: 10.8555008 (GCs = 390) ArrayList của Int32
00: 00: 02.5427847 (GCs = 4) Danh sách <Chuỗi>
00: 00: 02.7944831 (GCs = 7) ) ArrayList của Chuỗi

Kết quả ở đây cho thấy rằng sử dụng thuật toán List chung với loại Int32 nhanh hơn nhiều so với sử dụng thuật toán ArrayList không chung với Int32. Trong thực tế, sự khác biệt là phi thường: 1,6 giây so với gần 11 giây. Nhanh hơn 7 lần ! Ngoài ra, việc sử dụng loại giá trị (Int32) với ArrayList gây ra rất nhiều hoạt động đấm bốc xảy ra, dẫn đến việc thu thập được 390 bộ sưu tập rác. Trong khi đó, thuật toán List yêu cầu 6 bộ sưu tập rác.


1

Tôi nghĩ rằng, sự khác biệt giữa ArrayListList<T>là:

  1. List<T>, trong đó T là loại giá trị nhanh hơn ArrayList. Đây là vìList<T> tránh đấm bốc / bỏ hộp (trong đó T là loại giá trị).
  2. Nhiều nguồn tin cho biết - thường là ArrayList được sử dụng chỉ để tương thích ngược. (không phải là một sự khác biệt thực sự, nhưng tôi nghĩ đó là lưu ý quan trọng).
  3. Phản xạ là dễ dàng hơn với nongeneric ArrayListsau đóList<T>
  4. ArrayListIsSynchronizedtài sản. Vì vậy, thật dễ dàng để tạo và sử dụng đồng bộ hóa ArrayList. Tôi đã không tìm thấy IsSynchronizedtài sản cho List<T>. Ngoài ra, hãy nhớ rằng loại đồng bộ hóa này tương đối không hiệu quả, 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. ArrayListcó thuộc ArrayList.SyncRoottính có thể được sử dụng để đồng bộ hóa ( msdn ). List<T>không có SyncRoottài sản, vì vậy trong cấu trúc sau, bạn cần sử dụng một số đối tượng nếu bạn sử dụng List<T>:

    ArrayList myCollection = new ArrayList();
    lock(myCollection.SyncRoot) //  ofcourse you can use another object for this goal
    {
        foreach (object item in myCollection)
        {
            // ...
        }
    }

0

Như đã đề cập trong tài liệu .NET Framework

Chúng tôi không khuyên bạn nên sử dụng ArrayListlớp học để phát triển mới. Thay vào đó, chúng tôi khuyên bạn nên sử dụng List<T> lớp chung . CácArrayList lớp học được thiết kế để giữ các bộ sưu tập không đồng nhất của các đối tượng. Tuy nhiên, nó không phải lúc nào cũng cung cấp hiệu suất tốt nhất. Thay vào đó, chúng tôi khuyên bạn nên như sau:

  • Đối với một bộ sưu tập các đối tượng không đồng nhất, hãy sử dụng List<Object> (trong C #) hoặc List(Of Object)(trong Visual Basic).
  • Đối với một bộ sưu tập các đối tượng đồng nhất, sử dụng List<T>lớp.

Xem thêm Bộ sưu tập không chung chung không nên được sử dụng

bảng hiển thị cách các loại bộ sưu tập không chung chung có thể được thay thế bằng các đối tác chung của chúng


-2

Sử dụng "Danh sách" bạn có thể ngăn lỗi truyền. Nó rất hữu ích để tránh một lỗi đúc thời gian chạy.

Thí dụ:

Tại đây (sử dụng ArrayList) bạn có thể biên dịch mã này nhưng bạn sẽ thấy lỗi thực thi sau này.

    // 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.
        }
    }

Điều này thêm gì ngoài các câu trả lời đã đưa ra ba năm trước đó? Nó có nguyên văn gần như nguyên văn, không liên kết với nguồn, không định dạng đúng, v.v.
Douglas Zare

-3

Đối với tôi tất cả về việc biết dữ liệu của bạn. Nếu tôi tiếp tục mở rộng mã của mình trên cơ sở hiệu quả, tôi sẽ phải chọn tùy chọn Danh sách làm cách giải mã dữ liệu của mình với bước không cần thiết là luôn tự hỏi về các loại, đặc biệt là 'Loại tùy chỉnh'. Nếu máy hiểu được sự khác biệt và có thể xác định được nó thuộc loại dữ liệu nào tôi thực sự đang xử lý thì tại sao tôi phải cản trở và lãng phí thời gian để vượt qua các định hướng của 'NẾU THÌ ELSE'? Triết lý của tôi là để máy làm việc cho tôi thay vì tôi làm việc trên máy? Biết được sự khác biệt duy nhất của các lệnh mã đối tượng khác nhau sẽ giúp cho mã của bạn trở nên hiệu quả.

Tom Johnson (Một lối vào ... Một lối ra)

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.