Warning: file_get_contents(/data/phpspider/zhask/data//catemap/8/linq/3.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# 如何添加IEnumerable<;T>;到现有的ICollection<;T>;_C#_Linq_Generics_Ienumerable - Fatal编程技术网

C# 如何添加IEnumerable<;T>;到现有的ICollection<;T>;

C# 如何添加IEnumerable<;T>;到现有的ICollection<;T>;,c#,linq,generics,ienumerable,C#,Linq,Generics,Ienumerable,给定现有的ICollection实例(例如dest),从IEnumerable添加项的最有效和可读的方法是什么 在我的用例中,我有一种实用方法Collect(IEnumerable items),它返回一个新的ICollection,其中包含items中的元素,因此我采用以下方法: public static ICollection<T> Collect<T>(IEnumerable<T> items) where T:ICollection<T>

给定现有的
ICollection
实例(例如
dest
),从
IEnumerable
添加项的最有效和可读的方法是什么

在我的用例中,我有一种实用方法
Collect(IEnumerable items)
,它返回一个新的
ICollection
,其中包含
items
中的元素,因此我采用以下方法:

public static ICollection<T> Collect<T>(IEnumerable<T> items) where T:ICollection<T>
{
    ...
    ICollection<T> dest = Activator.CreateInstance<T>();
    items.Aggregate(dest, (acc, item) => { acc.Add(item); return acc; });
    ...
    return dest;
}
公共静态ICollection收集(IEnumerable items),其中T:ICollection
{
...
ICollection dest=Activator.CreateInstance();
聚合(dest,(acc,item)=>{acc.Add(item);return acc;});
...
返回目的地;
}
问题:有什么“更好”的方法(更有效的方法)吗

UPDATE:我认为
Aggregate()
的使用非常流畅,没有调用
ToList().ForEach()
那么低效。但它看起来不太可读。由于没有其他人同意使用
Aggregate()
我想了解一下您不使用
Aggregate()
的原因

items.ToList().ForEach(dest.Add);
如果不想创建新的集合实例,请创建一个扩展方法

public static class Extension
{
    public static void AddRange<T>(this ICollection<T> source, IEnumerable<T> items)
    {
        if (items == null)
        {
            return;
        }

        foreach (T item in items)
        {
            source.Add(item);
        }
    }
}
公共静态类扩展
{
公共静态void AddRange(此ICollection源,IEnumerable items)
{
if(items==null)
{
返回;
}
foreach(项目中的T项目)
{
来源.添加(项目);
}
}
}
然后,您可以按如下方式编辑代码:

        ICollection<T> dest = ...;
        IEnumerable<T> items = ...;
        dest.AddRange(items);
ICollection dest=。。。;
IEnumerable items=。。。;
目的地添加范围(项目);
只需使用:

如果
dest
实际上已经是一个列表,并且您想要修改它,请使用:


更新

如果必须向
ICollection
method参数添加项,则可以使用以下扩展:

public static void AddRange<T>(this ICollection<T> collection, IEnumerable<T> seq)
{
    List<T> list = collection as List<T>;
    if (list != null)
        list.AddRange(seq);
    else
    {
        foreach (T item in seq)
            collection.Add(item);
    }
}
publicstaticvoidaddrange(此ICollection集合,IEnumerable seq)
{
列表=集合为列表;
如果(列表!=null)
列表.添加范围(seq);
其他的
{
foreach(序号中的T项)
集合。添加(项目);
}
}
//

public static void Foo<T>(ICollection<T> dest)
{
    IEnumerable<T> items = ... 
    dest.AddRange(items);
}
publicstaticvoidfoo(ICollection dest)
{
IEnumerable items=。。。
目的地添加范围(项目);
}
效率最高的:

foreach(T item in itens) dest.Add(item)
items.Aggregate(dest, (acc, item) => { acc.Add(item); return acc; });
可读性最强(但效率低下,因为它正在创建一个一次性列表):

可读性较差,但效率不高:

foreach(T item in itens) dest.Add(item)
items.Aggregate(dest, (acc, item) => { acc.Add(item); return acc; });

就我个人而言,我赞同@ckruczek对
foreach
循环的评论:

foreach (var item in items)
    dest.Add(item);
简单、干净,几乎每个人都能立即理解它的功能

如果您坚持某些方法调用隐藏循环,那么有些人会为
IEnumerable
定义一个自定义的
ForEach
扩展方法,类似于为
List
定义的方法。实现过程非常简单:

public static void ForEach<T>(this IEnumerable<T> source, Action<T> action) {
    if (source == null) throw new ArgumentNullException(nameof(source));
    if (action == null) throw new ArgumentNullException(nameof(action));
    foreach (item in source)
        action(item);
}

我自己看不出它有什么好处,但也没有缺点。

我们实际上为此编写了一个扩展方法(以及一系列其他ICollection扩展方法):

注意:如果要使用
List.AddRange()
如果基础集合的类型为
List
,则可以实现如下扩展方法:

public static void AddRange<T>(this ICollection<T> collection, IEnumerable<T> source)
{
    var asList = collection as List<T>;

    if (asList != null)
    {
        asList.AddRange(source);
    }
    else
    {
        foreach (T item in source)
        {
            collection.Add(item);
        }
    }
}
publicstaticvoidaddrange(此ICollection集合,IEnumerable源代码)
{
var asList=集合作为列表;
if(asList!=null)
{
asList.AddRange(源);
}
其他的
{
foreach(源中的T项)
{
集合。添加(项目);
}
}
}

我会考虑滥用<代码>聚合>代码>扩展方法。@ CODOR,我与您分享关于可变共享状态的感受。但我没有找到一个“更便宜”的替代方案。为什么不简单的for循环并将项目添加到
dest
?LINQ中的副作用非常可怕。
add
有副作用,即改变您添加到的集合。也许
AddRange
?顺便说一句,您丢弃了返回值。@SebastianSchulz
ToList()
将创建一个新实例(在本例中为临时实例),该实例稍后将被GC丢弃。我认为它没有更高的效率。@UweKeim
AddRange
仅在
列表
1中提供<代码>i收集
没有添加范围2。在任何其他短代码中,我们将创建一个新的集合实例。=>
.Concat
创建一个新列表,以此类推…@MiguelGamboa:如果你不想要一个新实例,那么除了为每个列表创建一个新实例之外,没有其他方法。但是您可以创建一个扩展方法来为您实现这一点。然后可以直接调用
items.ForEach(dest.Add)
为什么不直接为
ICollection
添加
AddRange
扩展方法,而不是
ForEach
?这将使api更干净,并将减少操作开销。@Leri这不是一个坏主意,但它更复杂。可用于
列表的
AddRange
比一系列
Add
s(如果可能)执行得更好。您可能为
ICollection
添加的自定义
AddRange
应该具有相同的效果(如果可能,也可以)。如果实现无条件地转换为重复调用
ICollection.Add
,IMO会产生误导。Eric Lippert的强制性博客文章:“foreach”vs foreach“:@Chips_100我大体上同意埃里克·利珀特(Eric Lippert)所说的话,但我不确定我是否相信这一点。例如,F#提供了
Seq.iter
,这与
IEnumerable
ForEach
方法完全相同。将惰性评估和副作用结合起来是非常危险的,但不提供这种方法甚至不能将与之相关的风险降至最低。ToList.ForEach是最笨拙的方法之一。您正在创建一个一次性列表,以便能够使用
list.ForEach
。因此,这将枚举要填充的整个集合
public static void ForEach<T>(this IEnumerable<T> source, Action<T> action) {
    if (source == null) throw new ArgumentNullException(nameof(source));
    if (action == null) throw new ArgumentNullException(nameof(action));
    foreach (item in source)
        action(item);
}
items.ForEach(dest.Add);
public static class CollectionExt
{
    public static void AddRange<T>(this ICollection<T> collection, IEnumerable<T> source)
    {
        Contract.Requires(collection != null);
        Contract.Requires(source != null);

        foreach (T item in source)
        {
            collection.Add(item);
        }
    }
}
ICollection<int> test = new List<int>();
test.AddRange(new [] {1, 2, 3});
public static void AddRange<T>(this ICollection<T> collection, IEnumerable<T> source)
{
    var asList = collection as List<T>;

    if (asList != null)
    {
        asList.AddRange(source);
    }
    else
    {
        foreach (T item in source)
        {
            collection.Add(item);
        }
    }
}