Sự khác biệt giữa ArrayList
và List<>
trong C # là gì?
Có phải chỉ List<>
có một loại trong khi ArrayList
không?
List<>
nói chung, trong khi người ta hỏi về List<object>
cụ thể
Sự khác biệt giữa ArrayList
và List<>
trong C # là gì?
Có phải chỉ List<>
có một loại trong khi ArrayList
không?
List<>
nói chung, trong khi người ta hỏi về List<object>
cụ thể
Câu trả lời:
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 T
có loại giá trị trong ArrayList
trường hợp). ArrayList
chỉ đơn giản là lưu trữ object
tà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ỳ Cast
hoặc OfType
cuộc gọi nào).
ArrayList
thuộ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 ArrayList
mã 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ó.
ArrayList
trong thời gian chạy. Mặc dù vậy, nó sẽ yêu cầu diễn viên ArrayList
.
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
Để thêm vào các điểm trên. Sử dụng ArrayList
trong 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 ArrayList
19 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
Một sự khác biệt khác để thêm là liên quan đến Đồng bộ hóa luồng.
ArrayList
cung 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
ArrayList
nế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.
Câu trả lời đơn giản là
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/
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/
ArrayList
là 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ó.
ArrayList
không phải là loại an toàn trong khi đó List<T>
là loại an toàn. Đơn giản :).
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ì ArrayList
Thêm chỉ lấy object
tham 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 ArrayList
vs List<T>
:
Đó 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:
Tôi đã viết một phân tích chi tiết về những gì diễn ra với ArrayList
kị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ỗiKế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.
Tôi nghĩ rằng, sự khác biệt giữa ArrayList
và List<T>
là:
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ị).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).ArrayList
sau đóList<T>
ArrayList
có IsSynchronized
tà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 IsSynchronized
tà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
ArrayList
có thuộc ArrayList.SyncRoot
tính có thể được sử dụng để đồng bộ hóa ( msdn ). List<T>
không có SyncRoot
tà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)
{
// ...
}
}
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
ArrayList
lớp học để phát triển mới. Thay vào đó, chúng tôi khuyên bạn nên sử dụngList<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ặcList(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
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 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)