IList 변수에 항목 범위를 추가하는 방법


81

에 대한 AddRange()방법 이 없습니다 IList<T>.

항목을 IList<T>반복하고 Add()메서드를 사용하지 않고 항목 목록을에 추가하려면 어떻게 해야합니까?

답변:


66

AddRange 정의됩니다 List<T>인터페이스가 아니라 있습니다.

에 대한 액세스 권한을 얻기 위해 List<T>대신 변수를 선언 IList<T>하거나 캐스트 할 List<T>수 있습니다 AddRange.

((List<myType>)myIList).AddRange(anotherList);

int로서 이것은 좋은 방법 (아래 설명 참조)없는 IList<T>힘이 되지List<T>있지만, 인터페이스를 구현하고 매우가 없습니다 수있는 몇 가지 다른 종류의 AddRange코드가를 throw 할 때와 같은 경우에, 당신은 발견 할 것이다 - 방법 런타임에 예외입니다.

따라서 유형이 실제로 a라는 List<T>것을 확실히 알지 못하는 한 AddRange.

이를 수행하는 한 가지 방법은 is 또는 as 연산자를 사용하여 형식을 테스트하는 것입니다 (C # 7부터).

if(myIList is List<T>)
{
   // can cast and AddRange
}
else
{
   // iterate with Add
}

2
@ mohsen.d-유형이 생성 된 경우 생성 된 코드를 변경하고 싶지 않습니다 (덮어 쓰기 가능성이 있으므로). Concat@Self_Taught_Programmer 가 대답 했듯이 LINQ를 캐스팅하거나 사용하십시오 .
Oded

2
@ mohsen.d-그것이 당신의 코드라면 타입을 다음과 같이 선언 List<T>하는 것이 좋을 것입니다 (또는 이것이 당신에게 좋은 선택이 아니라면, AddRange지역화를 유지 해야하는 곳에서 캐스트를하십시오 -이것은 매우 저렴한 작업입니다.) ).
Oded

53
아니, 아니. 이것이 IList <T> 인 이유는 이것이 List <T> 구현이 아닌 다른 것일 수 있기 때문입니다. AddRange 메서드가 정말로 필요한 경우 BlackjacketMack에 표시된대로 확장 메서드를 작성합니다.
Derek Greer 2015

6
그것으로이받은 많은 upvotes 명확하게 같은 것을 던져 버릴거야 왜 생각이 InvalidCastException이외에서 사용하는 경우 List<T>(예를 들어, 배열).
bashis

3
그러나 캐스팅은 좋은 생각이 아닙니다. 성능 오버 헤드가 발생할 수 있습니다.
굴 Ershad

79

List 에 대한 C # 소스 코드를 보면 보면 List.AddRange ()에 간단한 루프가 해결하지 못하는 최적화가 있다고 생각합니다. 따라서 확장 메서드는 IList가 List인지 확인하고, 그렇다면 기본 AddRange ()를 사용해야합니다.

소스 코드를 살펴보면 .NET 사용자가 .ToList ()와 같은 작업을 위해 자체 Linq 확장에서 유사한 작업을 수행하는 것을 볼 수 있습니다 (목록 인 경우 캐스트 ... 그렇지 않으면 생성).

public static class IListExtension
{
    public static void AddRange<T>(this IList<T> list, IEnumerable<T> items)
    {
        if (list == null) throw new ArgumentNullException(nameof(list));
        if (items == null) throw new ArgumentNullException(nameof(items));

        if (list is List<T> asList)
        {
            asList.AddRange(items);
        }
        else
        {
            foreach (var item in items)
            {
                list.Add(item);
            }
        }
    }
}

6
최적화 관점에서 실제로 여기 list에서 List<T>두 번 캐스팅 하고 있습니다. 그중 하나는 as키워드 로 최적화 할 수 있습니다 .
bashis

@bashis 좋은 전화. 나는 항상 새로운 변수의 GC 정리와 이중 캐스트의 비용에 대해 앞뒤로 이동합니다. 그러나 우리는 실제로 var listCasted = list as List <T>; if (listCasted! = null) ... 아마도 c # 6 선언식이이 패턴을 변경할 것입니다 : if (myVar.As (out myVarCasted)) myVarCasted ...)
BlackjacketMack

언급 된 최적화로 코드를 업데이트 할 수 있습니까? 나는 아직 최신 기능에 능통하지 않습니다. @BlackjacketMack

2
@zuckerthoben-두 가지 접근 방식을 모두 사용하여 백만 번의 반복 테스트를 실행했으며 성능에는 차이가 없었습니다. 그래서 나는 그것을 최적화라고 부르지 않을 것입니다. 또한 코드 줄을 추가합니다 (그러나 괄호 캐스팅을 줄입니다). 어쨌든 요즘에는 'as'를 사용할 것입니다. var listCasted = list as List <T>; if (listCasted! = null) {listCasted.AddRange (items);}. 대답 IMHO를 업데이트 할 가치는 없지만 구문 대안으로 소개하는 것이 좋습니다.
BlackjacketMack

2
지금부터 당신이 할 수있는if (list is List<T> castedList) { castedList.AddRange(items); }
앙드레 만타

23

다음과 같이 할 수 있습니다.

IList<string> oIList1 = new List<string>{"1","2","3"};
IList<string> oIList2 = new List<string>{"4","5","6"};
IList<string> oIList3 = oIList1.Concat(oIList2).ToList();

그래서, 기본적으로는 사용하는 것이 Concat()확장과 ToList()같은 유사한 기능을 얻을 AddRange().

출처


1
귀하의 접근 방식의 문제 Enumerable.Concat는에 의해 구현되고 System.Linq.Enumerable해당 메서드의 반환 값이 IEnumerable<TSource>이므로 다시 캐스팅해서는 안된다고 생각합니다 IList<TSource>. 소스 코드를 확인하지 않고는 알 수없는 구현 세부 정보로 인해 다른 것을 반환 할 수 있습니다. 하지만 변경되지 않을 것이라는 보장은 없습니다. 따라서 여러 .NET 버전을 지원할 때는 특별한주의를 기울여야합니다.
jweyrich

8

다음과 같은 확장 메서드를 작성할 수도 있습니다.

internal static class EnumerableHelpers
{
    public static void AddRange<T>(this IList<T> collection, IEnumerable<T> items)
    {
        foreach (var item in items)
        {
            collection.Add(item);
        }
    }
}

용법:

        IList<int> collection = new int[10]; //Or any other IList
        var items = new[] {1, 4, 5, 6, 7};
        collection.AddRange(items);

여전히 항목에 대해 반복되지만 호출 할 때마다 반복을 작성하거나 캐스팅 할 필요가 없습니다.


2

LINQ를 사용하는 또 다른 대답은 추가하려는 것이 a List<T>이거나 호출 할 수 ToList()있는 경우입니다.

IEnumerable<string> toAdd = new string[] {"a", "b", "c"};
IList<string> target = new List<string>();

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