2009-09-25 15 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