C# 将范围添加到集合

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/1474863/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-06 17:54:14  来源:igfitidea点击:

AddRange to a Collection

c#collectionsc#-3.0extension-methods

提问by TrueWill

A coworker asked me today how to add a range to a collection. He has a class that inherits from Collection<T>. There's a get-only property of that type that already contains some items. He wants to add the items in another collection to the property collection. How can he do so in a C#3-friendly fashion? (Note the constraint about the get-only property, which prevents solutions like doing Union and reassigning.)

今天一位同事问我如何将范围添加到集合中。他有一个继承自Collection<T>. 有一个该类型的 get-only 属性已经包含一些项目。他想将另一个集合中的项目添加到属性集合中。他怎么能以 C#3 友好的方式做到这一点?(请注意关于 get-only 属性的约束,这会阻止诸如执行 Union 和重新分配之类的解决方案。)

Sure, a foreach with Property. Add will work. But a List<T>-style AddRange would be far more elegant.

当然,一个带有属性的 foreach。添加将起作用。但是一个List<T>风格的 AddRange 会优雅得多。

It's easy enough to write an extension method:

编写扩展方法很容易:

public static class CollectionHelpers
{
    public static void AddRange<T>(this ICollection<T> destination,
                                   IEnumerable<T> source)
    {
        foreach (T item in source)
        {
            destination.Add(item);
        }
    }
}

But I have the feeling I'm reinventing the wheel. I didn't find anything similar in System.Linqor morelinq.

但我感觉我正在重新发明轮子。我在System.Linqor morelinq 中没有找到类似的东西

Bad design? Just Call Add? Missing the obvious?

设计不好?只是调用添加?缺少明显的?

采纳答案by Reed Copsey

No, this seems perfectly reasonable. There is a List<T>.AddRange()method that basically does just this, but requires your collection to be a concrete List<T>.

不,这似乎完全合理。有一个List<T>.AddRange()方法基本上就是这样做的,但要求您的集合是一个具体的List<T>.

回答by Marcus Griep

The C5 Generic Collections Libraryclasses all support the AddRangemethod. C5 has a much more robust interface that actually exposes all of the features of its underlying implementations and is interface-compatible with the System.Collections.GenericICollectionand IListinterfaces, meaning that C5's collections can be easily substituted as the underlying implementation.

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

回答by jvitor83

Remember that each Addwill check the capacity of the collection and resize it whenever necessary (slower). With AddRange, the collection will be set the capacity and then added the items (faster). This extension method will be extremely slow, but will work.

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

回答by Jonathan Jansen

You could add your IEnumerable range to a list then set the ICollection = to the list.

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

        IEnumerable<T> source;

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

        ICollection<item> destination = list;

回答by rymdsmurf

Try casting to List in the extension method before running the loop. That way you can take advantage of the performance of List.AddRange.

在运行循环之前尝试在扩展方法中强制转换为 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);
        }
    }
}

回答by Matas Vaitkevicius

Since .NET4.5if you want one-liner you can use System.Collections.GenericForEach.

因为.NET4.5如果你想要一个班轮,你可以使用System.Collections.GenericForEach。

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

or even shorter as

甚至更短

source.ForEach(destination.Add);

Performance-wise it's the same as for each loop (syntactic sugar).

在性能方面,它与每个循环(语法糖)相同。

Also don'ttry assigning it like

不要尝试分配它

var x = source.ForEach(destination.Add) 

cause ForEachis void.

原因ForEach是无效的。

Edit:Copied from comments, Lipert's opinion on ForEach

编辑:从评论中复制,Lipert 对 ForEach 的看法

回答by Katarina Kelam

Or you can just make an ICollection extension like this:

或者你可以像这样制作一个 ICollection 扩展:

 public static ICollection<T> AddRange<T>(this ICollection<T> @this, IEnumerable<T> items)
    {
        foreach(var item in items)
        {
            @this.Add(item);
        }

        return @this;
    }

Using it would be just like using it on a list:

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

collectionA.AddRange(IEnumerable<object> items);

回答by MovGP0

Here is a bit more advanced/production-ready version:

这是一个更高级/生产就绪的版本:

    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;
        }
    }