C#中的ArrayList与List <>


412

ArrayListList<>C#和有什么不一样?

是只有List<>一种类型而ArrayList没有吗?



5
这是一个很接近的问题,但我认为并非完全重复。这List<>是一般性的问题,而List<object>具体是有关的问题
goodeye 2015年

发现这个非常有用的博客,可能会有所帮助。:认为我应该分享链接 fintechexplained.blogspot.co.uk/2017/07/...
InfoLearner

Answers:


533

是的,差不多。List<T>是泛型类。它支持存储特定类型的值,而无需进行强制转换object(如果T是值类型,则将产生装箱/拆箱开销ArrayList)。ArrayList简单地存储object引用。作为一个通用的集合,List<T>实现了通用IEnumerable<T>接口,并且可以在LINQ容易地使用(而不需要任何CastOfType呼叫)。

ArrayList属于C#没有泛型的日子。不推荐使用List<T>ArrayList除非必须与使用它的旧API交互,否则不要在针对.NET> = 2.0的新代码中使用。


您介意解释为什么使用“拳击”而不是“广播”吗?这里发生什么拳击?是否分配/取消分配对象?
本杰明·格伦鲍姆

2
@BenjaminGruenbaum您是正确的,铸造会更通用。就是说,运行时的真正区别是在处理值类型时(这是我写“装箱”时所假定的)。对于引用类型,其行为实际上与ArrayList运行时相同。不过从静态上来说,它需要使用进行强制转换ArrayList
Mehrdad Afshari

我想知道框架是否应该将T限制为“对象”类型,因为ArrayList隐式允许这样做。
rajibdotnet

有关弃用未类型化集合的信息,请参阅被认为有害的泛型
Ant_222 '17

@ 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。
2013年

1
我为理由+1,但仍然可以对数组列表使用if(num is int){}来避免错误
Mina Gabriel

防止投放错误和装箱费用。一般而言,使用泛型的原因很多。
marsze

26

要补充以上几点。使用ArrayList在64位操作系统花费的时间比使用32位操作系统的2倍的内存。同时,通用列表List<T>将使用比ArrayList。低得多的内存。

例如,如果我们ArrayList在32位中使用19MB的内存,则在64位中将占用39MB的内存。但是,如果您拥有List<int>32位8MB 的通用列表,那么64位仅需8.1MB,与ArrayList相比,差距是481%。

来源:原始类型和64位的ArrayList与通用列表


5
仅对存储值类型有效,对引用类型无效。差异是由于arraylist只能包含指针,而数据本身需要存储在其他地方。另一方面,值类型可以直接存储在列表中。
Rasmus Damgaard Nielsen,2015年

19

要添加的另一个区别是关于线程同步。

ArrayList通过Synchronized属性提供一些线程安全性,该属性返回围绕集合的线程安全包装器。包装器通过在每个添加或删除操作上锁定整个集合来工作。因此,每个试图访问该集合的线程都必须等待其轮换获得一个锁。这是不可扩展的,并且可能导致大型集合的性能显着下降。

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

这里更多信息线程同步在.Net框架


我并不是说ArrayList如果可以避免就应该使用它,但这是一个愚蠢的原因。毕竟,包装器是完全可选的。如果不需要锁定或需要更精细的控制,请不要使用包装器。
Thorarin

1
如果需要线程安全,建议在考虑ArrayList之前先查看System.Collections.Concurrent命名空间。
Ykok

15

简单的答案是,

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

请阅读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/




2

性能已经在几个答案中作为区别因素被提及,但是要解决“ 速度慢多少ArrayList”和“ 为什么整体速度变慢?”,请看下面。

每当将值类型用作元素时,使用都会使性能急剧下降ArrayList。考虑简单添加元素的情况。由于装箱继续-as ArrayList的Add只带object参数-垃圾收集器被触发执行比使用垃圾收集器更多的工作List<T>

时差是多少?至少比慢几倍List<T>。只要看看什么用的代码加入10万个INT值的情况ArrayListVS List<T>在此处输入图片说明

在“平均值”列中,运行时间差异为5倍,以黄色突出显示。还要注意每个垃圾收集数量的差异,用红色突出显示(GC数量/ 1000次运行)。

使用探查器快速查看发生的情况表明,大部分时间都花在了GC上,而不是实际添加元素。下面的棕色条表示阻止垃圾收集器的活动: 在此处输入图片说明

我在ArrayList这里https://mihai-albert.com/2019/12/15/boxing-performance-in-c-analysis-and-benchmark/编写了上述情况的详细分析。

杰弗里·里希特(Jeffrey Richter)的“通过C#进行CLR”中也有类似的发现。从第12章(泛型)开始:

[…]当我在计算机上编译并运行此程序的发行版(启用优化功能)时,得到以下输出。

00:00:01.6246959(GCs = 6)列表<Int32>
00:00:10.8555008(GCs = 390)
Array Int32的列表 00:00:02.5427847(GCs = 4)列表<String>
00:00:02.7944831(GCs = 7 )字符串的ArrayList

此处的输出显示,将Int32类型的泛型List算法与使用Int32的非泛型ArrayList算法相比要快得多。实际上,两者之间的差异是惊人的:1.6秒和11秒。快约7倍!此外,将值类型(Int32)与ArrayList一起使用会导致发生大量装箱操作,这将导致390个垃圾回收。同时,列表算法需要6个垃圾回收。


1

我认为ArrayList和之间的区别List<T>是:

  1. List<T>,其中T为value-type比快ArrayList。这是因为List<T>避免装箱/拆箱(其中T是值类型)。
  2. 许多消息人士说-通常ArrayList仅用于向后兼容。(不是真正的区别,但我认为这是重要的注意事项)。
  3. 反思是与非泛型容易ArrayListList<T>
  4. ArrayList拥有IsSynchronized财产。因此,创建和使用syncronized很容易ArrayList。我找不到的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可用于同步(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.
        }
    }

除了三年前给出的答案之外,这还增加了什么?它具有几乎相同的文本逐字逐句,没有链接到源,无需格式正确,等等
道格拉斯扎雷

-3

对我来说,所有有关了解您的数据的信息。如果我继续基于效率来扩展代码,则必须选择“列表”选项作为解密数据的一种方式,而无需总是担心类型(尤其是“自定义类型”)的不必要步骤。如果机器理解了差异并可以确定我实际上正在处理的是哪种类型的数据,那么为什么我要挡住路并浪费时间通过“ IF THEN ELSE”确定的旋转?我的理念是让机器为我工作而不是由我在机器上工作?知道不同目标代码命令的独特差异在使代码高效方面大有帮助。

汤姆·约翰逊(一个入口...一个出口)

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.