AddRange到集合

时间:2009-09-25 00:33:12

标签: c# collections c#-3.0 extension-methods

一位同事今天问我如何为一个系列添加一个范围。他有一个继承自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.Linqmorelinq中找不到类似内容。

糟糕的设计?只需致电添加?缺少明显的?

9 个答案:

答案 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 ICollectionIList接口的接口兼容,这意味着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);

在我看来,为这种操作提供一个扩展方法有点多余。