【问题标题】:ArrayList vs List<> in C#C# 中的 ArrayList 与 List<>
【发布时间】:2011-01-19 13:30:47
【问题描述】:

C# 中ArrayListList&lt;&gt; 有什么区别?

是不是只有List&lt;&gt; 有类型而ArrayList 没有?

【问题讨论】:

标签: c# .net list generics arraylist


【解决方案1】:

是的,差不多。 List&lt;T&gt; 是一个泛型类。它支持存储特定类型的值,而无需转换为object 或从object 转换(当TArrayList 情况下的值类型时,这将产生装箱/拆箱开销)。 ArrayList 仅存储 object 引用。作为一个泛型集合,List&lt;T&gt; 实现了泛型IEnumerable&lt;T&gt; 接口并且可以在LINQ 中轻松使用(不需要任何CastOfType 调用)。

ArrayList 属于 C# 没有泛型的时代。它已被 List&lt;T&gt; 弃用。您不应在以 .NET >= 2.0 为目标的新代码中使用 ArrayList,除非您必须与使用它的旧 API 交互。

【讨论】:

  • 您介意解释一下为什么您使用“拳击”而不是“铸造”吗?这里发生了什么拳击?对象是否已分配/释放?
  • @BenjaminGruenbaum 你是正确的,铸造会更普遍。也就是说,运行时的真正区别在于您处理值类型时(这是我在编写“装箱”时所假设的)。对于引用类型,其行为实际上与运行时的ArrayList 相同。不过静态地,它需要使用ArrayList 进行强制转换。
  • 我想知道框架是否应该将 T 限制为“对象”类型,因为 ArrayList 隐式允许这样做。
  • @Ant_222,该博客写于近 15 年前。我认为过去十年 + 的证据表明,仿制药是无害的。 :)
  • 我想(迟来的)添加到@ScottAdams 点:该博客讨论了Java 5 泛型实现的问题,这与.NET 的实现完全不同,它与这个问题无关.帖子中提到的“有害”示例在 .NET 中都没有问题,因此如果您想谈论 .NET 泛型的“陷阱”,您将需要使用不同的来源。
【解决方案2】:

使用List&lt;T&gt; 可以防止转换错误。避免 runtime 转换错误非常有用。

例子:

在这里(使用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。
  • i +1 证明,但您仍然可以对数组列表执行 if(num is int){} 以避免错误
  • 防止铸造错误和装箱开销。几乎是泛型的一般原因。
【解决方案3】:

补充以上几点。在 64 位操作系统中使用 ArrayList 比在 32 位操作系统中使用占用 2 倍的内存。同时,通用列表List&lt;T&gt; 将使用比ArrayList 低得多的内存。

例如,如果我们在 32 位中使用 19MB 的 ArrayList,则在 64 位中将需要 39MB。但是,如果您有一个 8MB 的 32 位通用列表 List&lt;int&gt;,那么在 64 位中只需要 8.1MB,与 ArrayList 相比相差 481%。

来源:ArrayList’s vs. generic List for primitive types and 64-bits

【讨论】:

  • 这仅适用于存储值类型,而不适用于引用类型。不同之处在于arraylist只能包含指针,而数据本身需要存储在其他地方。另一方面,值类型可以直接存储在列表中。
【解决方案4】:

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

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

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

更多信息在这里Thread Synchronization in the .Net Framework

【讨论】:

  • 我并不是说如果可以避免的话你​​应该使用ArrayList,但这是一个愚蠢的理由。毕竟包装器是完全可选的;如果您不需要锁定或需要更精细的控制,请不要使用包装器。
  • 如果你想要线程安全,我建议在考虑 ArrayList 之前先查看 System.Collections.Concurrent 命名空间。
【解决方案5】:

简单的答案是,

ArrayList 是非通用的

  • 它是一个对象类型,因此您可以在其中存储任何数据类型。
  • 您可以在 ArrayList 中存储任何值(值类型或引用类型),例如字符串、整数、员工和对象。 (注和)
  • 将进行装箱和拆箱。
  • 类型不安全。
  • 它比较旧。

列表是通用的

  • 它是一种类型的类型,因此您可以在运行时指定 T。
  • 您可以根据声明仅存储类型 T 的值(字符串或整数或雇员或对象)。 (注或)
  • 不会发生装箱和拆箱。
  • 类型安全。
  • 较新。

示例:

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

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

注意:在了解区别之前,您应该先了解泛型:https://docs.microsoft.com/en-us/dotnet/csharp/programming-guide/generics/

【讨论】:

  • 我很高兴它可以帮助你@zahrakhani
【解决方案6】:

ArrayList 是不同类型数据的集合,而List&lt;&gt; 是其自身依赖的相似类型的集合。

【讨论】:

    【解决方案7】:

    ArrayList 不是类型安全的,而 List&lt;T&gt; 是类型安全的。简单:)。

    【讨论】:

      【解决方案8】:

      在几个答案中已经提到了性能作为一个区别因素,但是为了解决“ArrayList 慢了多少?”和“为什么总体上比较慢?”,请看下面。

      只要将值类型用作元素,ArrayList 的性能就会急剧下降。考虑简单地添加元素的情况。由于拳击正在进行 - 因为 ArrayList 的 Add 只接受 object 参数 - 垃圾收集器被触发执行比 List&lt;T&gt; 更多的工作。

      时差是多少?至少比List&lt;T&gt; 慢几倍。看看代码在ArrayListList&lt;T&gt; 中添加 1000 万个 int 值会发生什么:

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

      使用分析器快速查看发生了什么表明大部分时间都花在了 GC 上,而不是实际添加元素。下面的棕色条表示阻塞垃圾收集器活动:

      我已经详细分析了上述ArrayList 场景发生的情况https://mihai-albert.com/2019/12/15/boxing-performance-in-c-analysis-and-benchmark/

      Jeffrey Richter 的“CLR via C#”中也有类似的发现。从第 12 章(泛型)开始:

      [...] 当我编译并运行发布版本时(已开启优化 在我的电脑上运行这个程序,我得到以下输出。

      00:00:01.6246959 (GCs=6) 列表
      00:00:10.8555008 (GCs=390) Int32 的 ArrayList
      00:00:02.5427847 (GCs= 4) 列表
      00:00:02.7944831 (GCs=7) ArrayList of String

      这里的输出显示 使用 Int32 类型的通用 List 算法是很多的 比使用 Int32 的非泛型 ArrayList 算法更快。在 事实上,差异是惊人的:1.6 秒与几乎 11 秒 秒。这大约快 7 倍!此外,使用值类型 (Int32) 与 ArrayList 导致发生大量装箱操作, 这会导致 390 次垃圾回收。同时,名单 算法需要 6 次垃圾回收。

      【讨论】:

        【解决方案9】:

        我认为,ArrayListList&lt;T&gt; 之间的区别是:

        1. List&lt;T&gt;,其中 T 是值类型比 ArrayList 快。这是 因为List&lt;T&gt; 避免装箱/拆箱(其中 T 是值类型)。
        2. 许多消息来源说 - 通常ArrayList 仅用于向后 兼容性。 (不是真正的区别,但我认为是 重要提示)。
        3. 使用非泛型 ArrayList 然后 List&lt;T&gt; 反射更容易
        4. ArrayList 具有 IsSynchronized 属性。所以,这很容易 创建和使用同步的ArrayList。我没有找到 List&lt;T&gt;IsSynchronized 属性。另外请记住,这种类型的同步效率相对较低,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&lt;T&gt; 没有 SyncRoot 属性,所以在 如果您使用List&lt;T&gt;,则需要使用以下构造:

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

        【讨论】:

          【解决方案10】:

          如 .NET Framework documentation 中所述

          我们不建议您将 ArrayList 类用于新的 发展。相反,我们建议您使用通用的List&lt;T&gt; 班级。 ArrayList 类旨在容纳异构 对象的集合。但是,它并不总是提供最好的 表现。相反,我们建议如下:

          • 对于异构对象集合,请使用 List&lt;Object&gt;(在 C# 中)或 List(Of Object)(在 Visual Basic 中)类型。
          • 对于对象的同类集合,请使用 List&lt;T&gt; 类。

          另见Non-generic collections shouldn't be used

          【讨论】:

            【解决方案11】:

            使用“列表”可以防止投射错误。避免运行时转换错误非常有用。

            例子:

            在这里(使用 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.
                    }
                }
            

            【讨论】:

            • 这比三年前伏藏给出的答案增加了什么?它具有几乎相同的逐字文本,没有链接到源,没有正确格式化等。
            【解决方案12】:

            对我来说,这就是了解您的数据。如果我继续在效率的基础上扩展我的代码,我将不得不选择 List 选项作为解密数据的一种方式,而无需总是想知道类型的不必要步骤,尤其是“自定义类型”。如果机器理解差异并且可以确定我实际处理的数据类型,那么我为什么要妨碍并浪费时间通过'IF THEN ELSE'确定的旋转?我的理念是让机器为我工作,而不是让我在机器上工作?了解不同目标代码命令的独特差异对提高代码效率大有帮助。

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

            【讨论】:

              猜你喜欢
              • 2010-09-28
              • 2018-02-23
              • 2016-03-02
              • 2019-01-12
              • 2012-06-08
              • 2013-09-26
              • 1970-01-01
              相关资源
              最近更新 更多