2009-09-25 41 views
65

一位同事今天问我如何添加范围到一个集合。他有一个继承自Collection<T>的类。有一种只包含某些项目的只能获取属性。他想将另一个集合中的项目添加到属性集合中。他如何以C#3友好的方式来做到这一点? (注意关于只能获取属性的约束,这会阻止像联合和重新分配这样的解决方案。)AddRange集合

当然,这是一个带有Property的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中没有找到类似的东西。

不好的设计?打电话添加?缺少显而易见的?

+3

请记住,来自LINQ的Q是'查询',并且实际上是关于数据检索,投影,转换等。修改现有集合实际上并不属于LINQ预期目的的领域,这就是为什么LINQ不提供任何开箱即用的功能。但扩展方法(特别是你的样本)将是理想的。 – Levi 2009-09-25 00:46:02

+0

一个问题,'ICollection '似乎没有'Add'方法。 http://msdn.microsoft.com/en-us/library/system.collections.icollection_methods(v=vs.100).aspx然而'收集'有一个。 – 2013-07-11 05:58:27

+0

@TimGoodman - 这是非通用界面。请参阅http://msdn.microsoft.com/en-us/library/92t2ye13.aspx – TrueWill 2013-07-11 17:26:12

回答

38

不,这似乎是非常合理的。有一个List<T>.AddRange()方法,基本上只是这样做,但需要您的收藏是一个具体的List<T>

+0

谢谢;非常真实,但大多数公共财产遵循MS准则,不是列表。 – TrueWill 2009-09-25 00:52:17

+4

是的 - 我之所以给它更多的理由是为什么我不认为这样做有问题。只是意识到它会比列表版本效率低(因为列表可以预分配) – 2009-09-25 01:12:18

1

C5 Generic Collections Library类都支持AddRange方法。 C5具有更强大的接口,它实际上暴露了其底层实现的所有功能,并且与接口兼容,这意味着C5的集合可以轻松替代为底层实现。

16

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

+3

要添加到此,每个添加也会有一个收集更改通知,而不是使用AddRange的一个批量通知。 – 2014-09-22 09:58:15

0

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

 IEnumerable<T> source; 

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

     ICollection<item> destination = list; 
+3

虽然此功能可以正常工作,但它违反了Microsoft指南,使集合属性为只读(http://msdn.microsoft.com/en-us/library/ms182327.aspx) – 2014-09-22 09:56:39

24

在运行循环之前,尝试将其转换为扩展方法的List。这样你可以利用List.AddRange的性能。由于.NET4.5如果你想要一个班轮

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); 
     } 
    } 
} 
+0

这可能有点问题,但会发生什么情况'''目的地'''集合不能被转换成'''列表'''? '''list'''是否自动变为'''null'''或是抛出的异常? – 2014-10-28 10:14:27

+1

'as'运算符永远不会抛出。如果'destination'不能被转换,'list'将会是null,'else'块会被执行。 – rymdsmurf 2014-10-29 12:04:20

+3

arrgggh!交换条件分支,为所有圣洁的爱! – nicodemus13 2016-07-15 16:11:46

15

can use System.Collections.Generic ForEach.

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

甚至更​​短

source.ForEach(destination.Add); 

性能方面是相同的每个循环(语法糖)。

而且尝试像

var x = source.ForEach(destination.Add) 

原因ForEach是无效的分配它。

+5

我个人与Lippert在这一个:http://blogs.msdn.com/b/ericlippert/archive /2009/05/18/foreach-vs-foreach.aspx – TrueWill 2015-01-15 16:21:07

+1

是否应该是source.ForEach(destination.Add)? – Frank 2016-09-08 20:04:33

+0

@弗兰克嗨弗兰克,固定感谢注意:) – 2016-09-09 06:30:10