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
?顺便说一句,您丢弃了返回值。@SebastianSchulzToList()
将创建一个新实例(在本例中为临时实例),该实例稍后将被GC丢弃。我认为它没有更高的效率。@UweKeimAddRange
仅在列表
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);
}
}
}