C#中的ArrayList与List <>

sca*_*man 383 .net c# generics list arraylist

ArrayListList<>#在C#之间有什么区别?

它只是List<>有类型而ArrayList不是吗?

Meh*_*ari 508

是的,差不多.List<T>是一个通用类.它支持存储特定类型的值而无需进行转换或从中获取object(当T在该ArrayList情况下为值类型时,会产生装箱/拆箱开销).ArrayList只是存储object参考.作为通用集合,List<T>实现通用IEnumerable<T>接口,可以在LINQ中轻松使用(无需任何CastOfType调用).

ArrayList属于C#没有泛型的日子.它被弃用了List<T>.ArrayList除非必须与使用它的旧API接口,否则不应使用面向.NET> = 2.0的新代码.

  • @BenjaminGruenbaum你是正确的,铸造会更一般.也就是说,运行时的真正区别在于你在处理值类型时(这就是我在写"装箱"时所假设的).对于引用类型,行为在运行时实际上与`ArrayList`相同.但静态地说,它需要使用`ArrayList`进行强制转换. (2认同)

小智 97

使用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
}
Run Code Online (Sandbox Code Playgroud)

如果使用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;
}
Run Code Online (Sandbox Code Playgroud)

参考: MSDN

  • i +1 的理由,但您仍然可以对数组列表执行 if(num is int){} 以避免错误 (2认同)

Ano*_*oop 23

添加到上述几点.使用ArrayList在64位操作系统将占用2个内存比使用32位操作系统.同时,通用列表List<T>将使用比内存低很多的内存ArrayList.

例如,如果我们ArrayList在32位中使用19MB,那么在64位中需要39MB.但是如果你有一个List<int>32位的8MB 通用列表,那么64位只需要8.1MB,与ArrayList相比,这是一个惊人的481%的差异.

Source:ArrayList与原始类型和64位的泛型List

  • 这仅适用于存储值类型,而不是引用类型.差异是由于arraylist只能包含指针,而数据本身需要存储在别处.另一方面,值类型可以直接存储在列表中. (4认同)

Nul*_*nce 18

要添加的另一个区别是线程同步.

ArrayList通过Synchronized属性提供一些线程安全性,该属性返回集合周围的线程安全包装器.包装器通过在每次添加或删除操作时锁定整个集合来工作.因此,尝试访问集合的每个线程必须等待轮到一个锁.这不可扩展,可能会导致大型集合的性能显着下降.

List<T>不提供任何线程同步; 用户代码必须在多个线程上同时添加或删除项目时提供所有同步.

更多信息,请访问.Net Framework中的线程同步


Ara*_*vin 8

简单的答案是,

ArrayList是非泛型的

  • 它是一种对象类型,因此您可以在其中存储任何数据类型。
  • 您可以将任何值(值类型或引用类型)存储在ArrayList中,例如字符串,int,employee和object。(注意和)
  • 装箱和拆箱将发生。
  • 输入不安全。
  • 比较老

清单是通用的

  • 它是类型类型,因此您可以在运行时指定T。
  • 您可以基于声明存储类型T的唯一值(字符串或int或员工或对象)。(注意或)
  • 装箱和拆箱将不会发生。
  • 输入安全。
  • 较新。

例:

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
Run Code Online (Sandbox Code Playgroud)

请阅读Microsoft官方文档https : //blogs.msdn.microsoft.com/kcwalina/2005/09/23/system-collections-vs-system-collection-generic-and-system-collections-objectmodel/

在此处输入图片说明

注意:在了解差异之前,您应该先了解泛型:https : //docs.microsoft.com/zh-cn/dotnet/csharp/programming-guide/generics/


Mih*_*ert 5

在几个答案中已经提到性能是一个区别因素,但是要解决 \xe2\x80\x9c慢了多少ArrayList\xe2\x80\x9d 和 \xe2\x80\x9c为什么整体速度较慢?\xe2\x80\x9d,看看下面。

\n\n

每当值类型用作元素时,性能都会急剧下降ArrayList。考虑简单添加元素的情况。由于装箱正在进行 - 因为ArrayList\xe2\x80\x99s Add 仅接受object参数 - 垃圾收集器被触发执行比List<T>.

\n\n

时差是多少?至少比 with 慢几倍List<T>。只需看一下将 1000 万个 int 值添加到ArrayListvs 的代码会发生什么List<T>:\n\n在此输入图像描述

\n\n

\xe2\x80\x99在 \xe2\x80\x98Mean\xe2\x80\x99 列中运行时间差异为5 倍,以黄色突出显示。另请注意每个垃圾收集次数的差异,以红色突出显示(GC 数量/1000 次运行)。

\n\n

使用分析器快速查看\xe2\x80\x99 发生的情况,表明大部分时间都花在了 GC 上,而不是实际添加元素。下面的棕色条代表阻塞的垃圾收集器活动:\n在此输入图像描述

\n\n

我\xe2\x80\x99在这里对上述ArrayList场景进行了详细分析https://mihai-albert.com/2019/12/15/boxing-performance-in-c-analysis-and-benchmark/

\n\n

Jeffrey Richter 通过 C#\xe2\x80\x9d 在 \xe2\x80\x9cCLR 中发现了类似的结果。来自第 12 章(泛型):

\n\n
\n

[\xe2\x80\xa6] 当我在计算机上编译并运行该程序的发布版本(打开优化)时,我得到以下输出。

\n\n

00:00:01.6246959 (GCs= 6) List<Int32>
\n 00:00:10.8555008 (GCs=390) Int32 ArrayList
\n 00:00:02.5427847 (GCs= 4) List<String>
\n 00:00 :02.7944831 (GCs= 7) 字符串数组列表

\n\n

此处的输出显示\n 使用 Int32 类型的泛型 List 算法比使用 Int32 类型的非泛型 ArrayList 算法要快得多。事实上,差异是惊人的:1.6 秒对比几乎 11 秒。那 \xe2\x80\x99s 快了约 7 倍!此外,将值类型 (Int32) 与 ArrayList 一起使用会导致发生大量装箱操作,从而导致 390 次垃圾回收。同时,List\n 算法需要 6 次垃圾回收。

\n
\n