오늘 동료가 컬렉션에 범위를 추가하는 방법을 물었습니다. 그는에서 상속하는 클래스가 있습니다 Collection<T>
. 이미 일부 항목을 포함하는 해당 유형의 가져 오기 전용 속성이 있습니다. 그는 다른 컬렉션의 항목을 속성 컬렉션에 추가하려고합니다. C # 3 친화적 인 방식으로 어떻게 그렇게 할 수 있습니까? (Union 수행 및 재 할당과 같은 솔루션을 방지하는 get-only 속성에 대한 제약에 유의하십시오.)
물론입니다. Property가있는 foreach입니다. 추가가 작동합니다. 그러나 List<T>
스타일 AddRange는 훨씬 더 우아합니다.
확장 메서드를 작성하는 것은 쉽습니다.
public static class CollectionHelpers
{
public static void AddRange<T>(this ICollection<T> destination,
IEnumerable<T> source)
{
foreach (T item in source)
{
destination.Add(item);
}
}
}
그러나 나는 바퀴를 재발 명하고 있다는 느낌이 있습니다. System.Linq
or morelinq 에서 비슷한 것을 찾지 못했습니다 .
나쁜 디자인? 그냥 전화 추가? 명백한 것을 놓치고 있습니까?
답변
아니요, 이건 완벽하게 합리적으로 보입니다. 기본적으로이 작업을 수행 하는 List<T>.
AddRange () 메서드가 있지만 컬렉션이 concrete이어야합니다 List<T>
.
답변
루프를 실행하기 전에 확장 메서드에서 List로 캐스팅 해보십시오. 이렇게하면 List.AddRange의 성능을 활용할 수 있습니다.
public static void AddRange<T>(this ICollection<T> destination,
IEnumerable<T> source)
{
List<T> list = destination as List<T>;
if (list != null)
{
list.AddRange(source);
}
else
{
foreach (T item in source)
{
destination.Add(item);
}
}
}
답변
때문에 .NET4.5
당신이 한 줄을 원하는 경우 사용할 수 System.Collections.Generic
를 ForEach를.
source.ForEach(o => destination.Add(o));
또는 더 짧게
source.ForEach(destination.Add);
성능면에서는 각 루프 (구문 설탕)와 동일합니다.
또한 다음 과 같이 할당 하지 마십시오.
var x = source.ForEach(destination.Add)
원인 ForEach
은 무효입니다.
편집 : 코멘트에서 복사, ForEach에 대한 Lipert의 의견
답변
각각 Add
은 컬렉션의 용량을 확인하고 필요할 때마다 크기를 조정합니다 (느림). 를 사용 AddRange
하면 컬렉션이 용량을 설정 한 다음 항목을 추가합니다 (더 빠르게). 이 확장 방법은 매우 느리지 만 작동합니다.
답변
다음은 좀 더 고급 / 생산 준비 버전입니다.
public static class CollectionExtensions
{
public static TCol AddRange<TCol, TItem>(this TCol destination, IEnumerable<TItem> source)
where TCol : ICollection<TItem>
{
if(destination == null) throw new ArgumentNullException(nameof(destination));
if(source == null) throw new ArgumentNullException(nameof(source));
// don't cast to IList to prevent recursion
if (destination is List<TItem> list)
{
list.AddRange(source);
return destination;
}
foreach (var item in source)
{
destination.Add(item);
}
return destination;
}
}
답변
C5 일반 컬렉션 라이브러리 클래스는 모든 지원 AddRange
방법을. C5에는 기본 구현의 모든 기능을 실제로 노출하는 훨씬 더 강력한 인터페이스가 있으며 System.Collections.Generic
ICollection
및 IList
인터페이스 와 인터페이스 호환이 가능합니다 . 즉, C5
의 컬렉션을 기본 구현으로 쉽게 대체 할 수 있습니다.
답변
IEnumerable 범위를 목록에 추가 한 다음 ICollection =을 목록에 설정할 수 있습니다.
IEnumerable<T> source;
List<item> list = new List<item>();
list.AddRange(source);
ICollection<item> destination = list;