如何将 IEnumerable<T> 添加到现有的 ICollection<T>
How can I add an IEnumerable<T> to an existing ICollection<T>
给定一个现有的 ICollection<T>
实例(例如 dest
)从 IEnumerable<T>
添加项目的最有效和可读的方法是什么?
在我的用例中,我有某种实用方法 Collect(IEnumerable items)
,其中 returns 一个新的 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;
}
问题:有没有“更好”的方法(更高效或可读)这样做?
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);
}
}
}
然后您可以像这样编辑您的代码:
ICollection<T> dest = ...;
IEnumerable<T> items = ...;
dest.AddRange(items);
只需使用Enumerable.Concat
:
IEnumerable<YourType> result = dest.Concat(items);
如果您想要 List<T>
作为结果,请使用 ToList
:
List<YourType> result = dest.Concat(items).ToList();
// perhaps:
dest = result;
如果 dest
实际上已经是一个列表,而您想修改它,请使用 AddRange
:
dest.AddRange(items);
更新:
如果您必须将项目添加到 ICollection<T>
方法参数,您可以使用此扩展:
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);
}
}
// ...
public static void Foo<T>(ICollection<T> dest)
{
IEnumerable<T> items = ...
dest.AddRange(items);
}
效率最高:
foreach(T item in itens) dest.Add(item)
最易读(但效率低下,因为它正在创建一个一次性列表):
items.ToList().ForEach(dest.Add);
可读性较差,但效率不低:
items.Aggregate(dest, (acc, item) => { acc.Add(item); return acc; });
就我个人而言,我会同意@ckruczek 对 foreach
循环的评论:
foreach (var item in items)
dest.Add(item);
简单、干净,几乎每个人都能立即理解它的作用。
如果您确实坚持某些方法调用隐藏循环,那么有些人会为 IEnumerable<T>
定义自定义 ForEach
扩展方法,类似于为 List<T>
定义的方法。实现很简单:
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);
我自己看不出有什么好处,但也没有坏处。
我们实际上为此编写了一个扩展方法(以及一堆其他 ICollection 扩展方法):
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()
:
上使用 AddRange()
ICollection<int> test = new List<int>();
test.AddRange(new [] {1, 2, 3});
注意:如果基础集合的类型为 List<T>
,如果您想使用 List<T>.AddRange()
,您可以像这样实现扩展方法:
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);
}
}
}
给定一个现有的 ICollection<T>
实例(例如 dest
)从 IEnumerable<T>
添加项目的最有效和可读的方法是什么?
在我的用例中,我有某种实用方法 Collect(IEnumerable items)
,其中 returns 一个新的 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;
}
问题:有没有“更好”的方法(更高效或可读)这样做?
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);
}
}
}
然后您可以像这样编辑您的代码:
ICollection<T> dest = ...;
IEnumerable<T> items = ...;
dest.AddRange(items);
只需使用Enumerable.Concat
:
IEnumerable<YourType> result = dest.Concat(items);
如果您想要 List<T>
作为结果,请使用 ToList
:
List<YourType> result = dest.Concat(items).ToList();
// perhaps:
dest = result;
如果 dest
实际上已经是一个列表,而您想修改它,请使用 AddRange
:
dest.AddRange(items);
更新:
如果您必须将项目添加到 ICollection<T>
方法参数,您可以使用此扩展:
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);
}
}
// ...
public static void Foo<T>(ICollection<T> dest)
{
IEnumerable<T> items = ...
dest.AddRange(items);
}
效率最高:
foreach(T item in itens) dest.Add(item)
最易读(但效率低下,因为它正在创建一个一次性列表):
items.ToList().ForEach(dest.Add);
可读性较差,但效率不低:
items.Aggregate(dest, (acc, item) => { acc.Add(item); return acc; });
就我个人而言,我会同意@ckruczek 对 foreach
循环的评论:
foreach (var item in items)
dest.Add(item);
简单、干净,几乎每个人都能立即理解它的作用。
如果您确实坚持某些方法调用隐藏循环,那么有些人会为 IEnumerable<T>
定义自定义 ForEach
扩展方法,类似于为 List<T>
定义的方法。实现很简单:
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);
我自己看不出有什么好处,但也没有坏处。
我们实际上为此编写了一个扩展方法(以及一堆其他 ICollection 扩展方法):
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()
:
AddRange()
ICollection<int> test = new List<int>();
test.AddRange(new [] {1, 2, 3});
注意:如果基础集合的类型为 List<T>
,如果您想使用 List<T>.AddRange()
,您可以像这样实现扩展方法:
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);
}
}
}