关于C:添加范围到集合

AddRange to a Collection

今天一位同事问我如何为收藏添加范围。他有一个从以东继承的阶级。该类型的get-only属性已包含某些项。他想将另一个集合中的项添加到属性集合中。他怎么能以一种友好的方式做到这一点?(注意get only属性的约束,这会阻止执行联合和重新分配等解决方案。)

当然,一个有属性的foreach。Add会起作用。但是,一个List样式的addrange将要优雅得多。

编写扩展方法非常简单:

1
2
3
4
5
6
7
8
9
10
11
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没有发现类似的东西。

糟糕的设计?只需调用ADD?错过了明显的?


不,这似乎很合理。有一个List.addrange()方法基本上就是这样做的,但需要您的集合是一个具体的List


在运行循环之前,尝试强制转换为在扩展方法中列出。这样就可以利用list.addrange的性能。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
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作前臂。

1
source.ForEach(o => destination.Add(o));

甚至更短

1
source.ForEach(destination.Add);

从性能上讲,它与每个循环(句法糖)相同。

也不要尝试像这样分配它

1
var x = source.ForEach(destination.Add)

因为ForEach无效。


记住,每个Add都将检查集合的容量,并在必要时调整其大小(较慢)。使用AddRange时,将设置收集容量,然后添加项目(更快)。这种扩展方法将非常缓慢,但会起作用。


c5通用集合库类都支持AddRange方法。c5有一个更加健壮的接口,它实际上公开了其底层实现的所有特性,并且与System.Collections.GenericICollectionIList接口兼容,这意味着C5的集合可以很容易地替换为底层实现。


或者您可以这样做一个ICollection扩展:

1
2
3
4
5
6
7
8
9
 public static ICollection<T> AddRange<T>(this ICollection<T> @this, IEnumerable<T> items)
    {
        foreach(var item in items)
        {
            @this.Add(item);
        }

        return @this;
    }

使用它就像在列表上使用它一样:

1
collectionA.AddRange(IEnumerable<object> items);


可以将IEnumerable范围添加到列表中,然后将ICollection=设置为列表。

1
2
3
4
5
6
        IEnumerable<T> source;

        List<item> list = new List<item>();
        list.AddRange(source);

        ICollection<item> destination = list;