一位同事今天问我如何为一个系列添加一个范围。他有一个继承自Collection<T>
的班级。这种类型的get-only属性已包含一些项目。他想将另一个集合中的项目添加到属性集合中。他怎么能以C#3友好的方式这样做呢? (请注意有关get-only属性的约束,这会阻止像执行Union和重新分配等解决方案。)
当然,有一个属性的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
或morelinq中找不到类似内容。
糟糕的设计?只需致电添加?缺少明显的?
答案 0 :(得分:53)
不,这看起来非常合理。有List<T>.
AddRange()方法基本上可以做到这一点,但要求您的集合是具体的List<T>
。
答案 1 :(得分:34)
在运行循环之前,尝试在扩展方法中转换为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);
}
}
}
答案 2 :(得分:23)
自.NET4.5
起,如果你想要单行,can use System.Collections.Generic
ForEach.
source.ForEach(o => destination.Add(o));
甚至更短
source.ForEach(destination.Add);
性能方面与每个循环(语法糖)相同。
同样不尝试分配
var x = source.ForEach(destination.Add)
原因ForEach
无效。
答案 3 :(得分:19)
请记住,每个Add
都会检查集合的容量,并在必要时调整其大小(较慢)。使用AddRange
,集合将设置容量,然后添加项目(更快)。这种扩展方法会非常慢,但会起作用。
答案 4 :(得分:1)
C5 Generic Collections Library类都支持AddRange
方法。 C5具有更强大的接口,实际上暴露了其底层实现的所有功能,并且与System.Collections.Generic
ICollection
和IList
接口的接口兼容,这意味着C5
可以很容易地将集合替换为底层实现。
答案 5 :(得分:0)
您可以将IEnumerable范围添加到列表中,然后将ICollection =设置为列表。
IEnumerable<T> source;
List<item> list = new List<item>();
list.AddRange(source);
ICollection<item> destination = list;
答案 6 :(得分:0)
或者您可以像这样进行ICollection扩展:
public static ICollection<T> AddRange<T>(this ICollection<T> @this, IEnumerable<T> items)
{
foreach(var item in items)
{
@this.Add(item);
}
return @this;
}
使用它就像在列表上使用它一样:
collectionA.AddRange(IEnumerable<object> items);
答案 7 :(得分:0)
这里是更高级/可用于生产的版本:
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;
}
}
答案 8 :(得分:0)
同意上面的一些人和 Lipert 的意见。 就我而言,经常这样做:
ICollection<int> A;
var B = new List<int> {1,2,3,4,5};
B.ForEach(A.Add);
在我看来,为这种操作提供一个扩展方法有点多余。