C #에서 ArrayList와 List <>


412

C # ArrayList과 의 차이점은 무엇입니까 List<>?

그렇지 않은 List<>유형 만 ArrayList있습니까?



5
가까운 질문이지만 정확하게 복제되지는 않는다고 생각합니다. 이것은 List<>일반적으로 물어 보는 반면에, List<object>구체적으로 묻습니다
— goodeye

이 매우 유용한 블로그를 찾았다면 도움이 될 것입니다. fintechexplained.blogspot.co.uk/2017/07/…
— InfoLearner

답변:


533

그렇습니다. List<T>일반 클래스입니다. 캐스팅하거나 캐스팅하지 않고 특정 유형의 값을 저장할 수 있습니다 object( T이 경우 값 유형 인 경우 boxing / unboxing 오버 헤드가 발생 함 ArrayList). ArrayList단순히 object참조 를 저장 합니다. 일반 컬렉션으로서 List<T>일반 IEnumerable<T>인터페이스를 구현하며 LINQ에서 쉽게 사용할 수 있습니다 ( Cast또는 OfType호출 하지 않아도 됨 ).

ArrayListC #에 제네릭이 없었던 날에 속합니다. 에 찬성하여 더 이상 사용되지 않습니다 List<T>. 당신은 사용하지 말아야 ArrayList새로운 코드에 그 목표 .NET> = 2.0 오래된 API와 인터페이스해야하지 않는 한 그것은 그.


왜 "캐스팅"이 아닌 "권투"를 사용했는지 설명해 주시겠습니까? 여기서 무슨 권투가 발생합니까? 객체가 할당 / 할당되지 않습니까?
— Benjamin Gruenbaum

2
@BenjaminGruenbaum 캐스팅이 더 일반적 일 것입니다. 즉, 런타임에서 실제 차이점은 값 유형을 처리 할 때입니다 ( "boxing"을 작성할 때 가정 한 것임). 참조 유형의 경우 동작은 ArrayList런타임 과 사실상 동일 합니다. 그러나 정적으로는로 캐스팅해야합니다 ArrayList.
— Mehrdad Afshari

ArrayList가 암시 적으로 허용하기 때문에 프레임 워크가 T를 "객체"유형으로 제한 해야하는지 궁금합니다.
— rajibdotnet

형식화되지 않은 컬렉션의 폐기에 대해서는 유해한 것으로 간주되는 제네릭
— Ant_222

@ Ant_222, 그 블로그는 거의 15 년 전에 작성되었습니다. 지난 10 년 동안의 증거는 제네릭이 해롭지 않다는 것을 보여주었습니다. :)
— 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가 더 이상 필요하지 않습니다.
— 전환

1
나는 정당화에 +1하지만 오류를 피하기 위해 배열 목록에 if (num is int) {} 할 수있다
— Mina Gabriel

캐스팅 오류 및 권투 오버 헤드를 방지하십시오. 제네릭의 일반적인 이유는 거의 같습니다.
— marsze

26

위의 포인트에 추가합니다. 사용하여 ArrayList64 비트 운영 시스템은 32 비트 운영체제에서 사용하는 것보다 2 배의 메모리 걸린다. 한편, 일반 목록 List<T>은보다 적은 메모리를 사용합니다 ArrayList.

예를 들어 ArrayList32 비트에서 19MB를 사용하는 경우 64 비트에서 39MB가 필요합니다. 그러나 List<int>32 비트 의 일반 8MB 목록이있는 경우 64 비트의 경우 8.1MB 만 사용되므로 ArrayList와 비교할 때 481 %의 차이가 있습니다.

출처 : 기본 유형 및 64 비트에 대한 ArrayList와 일반 목록


5
이는 참조 유형이 아닌 값 유형을 저장하는 경우에만 해당됩니다. 차이점은 arraylist는 포인터 만 포함 할 수 있고 데이터 자체는 다른 곳에 저장해야하기 때문입니다. 반면에 값 유형은 목록에 직접 저장할 수 있습니다.
— 라스무스 담 가드 닐슨

19

추가해야 할 또 다른 차이점은 스레드 동기화와 관련이 있습니다.

ArrayList컬렉션 주위의 스레드 안전 래퍼를 반환하는 Synchronized 속성을 통해 스레드 안전을 제공합니다. 랩퍼는 모든 추가 또는 제거 조작에서 전체 콜렉션을 잠그면 작동합니다. 따라서 컬렉션에 액세스하려는 각 스레드는 해당 차례가 하나의 잠금을 수행 할 때까지 기다려야합니다. 이는 확장 할 수 없으며 대규모 컬렉션의 경우 성능이 크게 저하 될 수 있습니다.

List<T>스레드 동기화를 제공하지 않습니다. 사용자 코드는 여러 스레드에서 동시에 항목을 추가하거나 제거 할 때 모든 동기화를 제공해야합니다.

자세한 내용 은 .Net Framework의 스레드 동기화


ArrayList피할 수 있다면 사용해야한다고 말하는 것은 아니지만 이것이 어리석은 이유입니다. 래퍼는 전적으로 선택 사항입니다. 잠금이 필요하지 않거나 더 세밀한 제어가 필요한 경우 래퍼를 사용하지 마십시오.
— Thorarin

1
스레드 안전성을 원한다면 ArrayList를 고려하기 전에 System.Collections.Concurrent 네임 스페이스를 살펴 보는 것이 좋습니다.
— Ykok

15

간단한 대답은

ArrayList는 제네릭이 아닙니다

  • 객체 유형이므로 모든 데이터 유형을 저장할 수 있습니다.
  • String, int, employee 및 object와 같은 값 (값 유형 또는 참조 유형)을 ArrayList에 저장할 수 있습니다. (참고 및)
  • 권투와 Unboxing이 일어날 것입니다.
  • 안전하지 않습니다.
  • 오래되었습니다.

일반 목록

  • 유형 유형이므로 런타임시 T를 지정할 수 있습니다.
  • 선언에 따라 유형 T (문자열 또는 정수 또는 직원 또는 객체)의 유일한 값을 저장할 수 있습니다. (참고 또는)
  • 권투와 Unboxing이 발생하지 않습니다.
  • 안전한 타입.
  • 최신입니다.

예:

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/

여기에 이미지 설명을 입력하십시오

참고 : 차이점을 이해하기 전에 Generics를 알아야합니다. https://docs.microsoft.com/en-us/dotnet/csharp/programming-guide/generics/


4

ArrayList서로 다른 유형의 데이터를 List<>수집 하는 반면 유사한 유형의 자체 depedencties를 수집합니다.


3

ArrayList형식이 안전하지만 형식이 안전하지 않습니다 List<T>. 단순 :).


2

성능은 이미 몇 가지 답변에서 차별화 요소로 언급되었지만“ 어느 정도 느린 ArrayList가요? ”및“ 왜 전체적으로 느려 집니까? ”, 아래를보세요.

값 유형이 요소로 사용될 때마다 성능이 크게 저하됩니다 ArrayList. 단순히 요소를 추가하는 경우를 고려하십시오. 권투가 계속 진행됨에 따라 ArrayListAdd는 object매개 변수 만 사용 하므로 가비지 수집기는보다 많은 작업을 수행하도록 트리거됩니다 List<T>.

시차는 얼마입니까? 보다 몇 배 이상 느립니다 List<T>. 10mil int 값을 ArrayListvs에 추가하는 코드에서 발생하는 일을 살펴보십시오 List<T>. 여기에 이미지 설명을 입력하십시오

'Mean'열에서 노란색으로 강조 표시된 런타임 차이는 5 배 입니다. 또한 각각에 대해 수행 된 가비지 콜렉션 수의 차이가 빨간색으로 강조 표시됩니다 (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) List <Int32>
00 : 00 : 10.8555008 (GCs = 390) Int32의
배열 목록 00 : 00 : 02.5427847 (GCs = 4) List <String>
00 : 00 : 02.7944831 (GCs = 7 ) 문자열의 ArrayList

여기서 출력은 Int32 유형으로 일반 목록 알고리즘을 사용하는 것이 Int32와 함께 제네릭이 아닌 ArrayList 알고리즘을 사용하는 것보다 훨씬 빠르다는 것을 보여줍니다. 실제로, 그 차이는 놀랍습니다 : 1.6 초 대 거의 11 초. ~ 7 배 빠릅니다 ! 또한 ArrayList에 값 유형 (Int32)을 사용하면 많은 복싱 작업이 발생하여 390 개의 가비지 수집이 발생합니다. 한편, List 알고리즘에는 6 개의 가비지 콜렉션이 필요했습니다.


1

나는 사이의 차이를 생각 ArrayList하고 List<T>있습니다 :

  1. List<T>여기서 T는 value-type보다 빠릅니다 ArrayList. 이것은 List<T>boxing / unboxing을 피하기 때문입니다 (여기서 T는 value-type입니다).
  2. 많은 출처에 따르면 일반적으로 ArrayList이전 버전과의 호환성을 위해서만 사용됩니다. (실제 차이는 없지만 중요한 메모라고 생각합니다).
  3. 비 제네릭 ArrayList을 사용 하면 반사가 더 쉽습니다.List<T>
  4. ArrayListIsSynchronized속성 이 있습니다. 따라서 syncronised를 쉽게 만들고 사용할 수 있습니다 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.SyncRootsyncronisation (사용할 수있는 속성 은 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 년 전에 주어진 해답 용어 외에 무엇을 추가합니까? 소스에 연결하지 않고 서식을 올바르게 지정하지 않고 거의 동일한 텍스트를 그대로 사용합니다.
— Douglas Zare

-3

귀하의 데이터를 아는 것에 대한 모든 것. 효율성을 기준으로 코드를 계속 확장하려면 유형, 특히 '사용자 정의 유형'에 대해 항상 궁금해하는 불필요한 단계없이 데이터를 해독하는 방법으로 목록 옵션을 선택해야합니다. 기계가 그 차이를 이해하고 실제로 처리하고있는 데이터 유형이 무엇인지 판단 할 수 있다면 왜 'IF THEN ELSE'결정의 진행을 통해 방해가됩니까? 저의 철학은 기계 작업을하는 대신 기계를 작동시키는 것입니까? 다른 객체 코드 명령의 고유 한 차이점을 아는 것은 코드를 효율적으로 만드는 데 큰 도움이됩니다.

톰 존슨 (하나의 입구 ... 하나의 출구)

당사 사이트를 사용함과 동시에 당사의 쿠키 정책과 개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.