2009-09-25 12 views
65

Bir iş arkadaşım bugün koleksiyona nasıl bir aralık eklendiğimi sordu. O, Collection<T>'dan miras alan bir sınıfa sahip. Zaten bazı öğeler içeren bu tür bir get-only özelliği var. Başka bir koleksiyondaki eşyaları mülk koleksiyonuna eklemek istiyor. C# 3 dostu bir şekilde nasıl yapabilir? (Yalnızca alma ve yeniden atama gibi çözümleri engelleyen get-only özelliği hakkındaki kısıtlamaya dikkat edin.)Koleksiyona ekleSürü oluşturma

Elbette, Mülk sahibi olan bir foreach. Ekle çalışacaktır. Ama List<T> tarzı AddRange çok daha şık olurdu.

Bu bir uzantısı yöntemi yazmak kolay yeter:

public static class CollectionHelpers 
{ 
    public static void AddRange<T>(this ICollection<T> destination, 
            IEnumerable<T> source) 
    { 
     foreach (T item in source) 
     { 
      destination.Add(item); 
     } 
    } 
} 

Ama tekerleği yeniden ediyorum his var. System.Linq veya morelinq'da benzer bir şey bulamadım.

Bozuk tasarım? Sadece Çağrı Ekle? Açık olanı mı kaçırıyorsun?

+3

LINQ'dan Q'un 'sorgu' olduğunu ve gerçekten veri alma, yansıtma, dönüştürme vb. Ile ilgili olduğunu unutmayın.Mevcut koleksiyonları değiştirmek LINQ'un amaçlanan amacına gerçekten girmez, bu yüzden LINQ bunun için herhangi bir şey sunmaz. Ancak uzatma yöntemleri (ve özellikle örneğiniz) bunun için idealdir. – Levi

+0

Tek sorun, 'ICollection ' '' '' yöntemine sahip görünmüyor. http://msdn.microsoft.com/en-us/library/system.collections.icollection_methods(v=vs.100).aspx 'Koleksiyon ' bir tane var. –

+0

@TimGoodman - Bu jenerik olmayan bir arayüz. Bkz. Http://msdn.microsoft.com/en-us/library/92t2ye13.aspx – TrueWill

cevap

38

Hayır, bu kesinlikle makul gözüküyor. Temel olarak bunu yapan bir List<T>.AddRange() yöntemi vardır, ancak koleksiyonunuzun beton List<T> olmasını gerektirir.

+0

Teşekkürler; Çok doğru, ancak çoğu kamu malı MS kurallarına uyuyor ve Listeler değil. – TrueWill

+4

Evet - Bunu yapmayla ilgili bir sorun olduğunu düşünmüyorum diye mantığa daha çok veriyordum. Sadece Listesinden daha az verimli olacağını fark edin (liste ön tahsis edebilir) –

1

C5 Generic Collections Library sınıflarının tümü, AddRange yöntemini destekler. C5, aslında temelindeki uygulamaların tüm özelliklerini ortaya koyan ve System.Collections.GenericIList arabirimleriyle uyumlu olan çok daha sağlam bir arabirime sahiptir, yani C5 koleksiyonları temel uygulama olarak kolayca değiştirilebilir.

16

Her bir Add koleksiyonunun kapasitesini kontrol edip gerektiğinde yeniden boyutlandıracağını unutmayın (daha yavaş). AddRange ile, koleksiyon kapasitesi ayarlanacak ve daha sonra öğeleri (daha hızlı) ekleyecektir. Bu uzatma yöntemi çok yavaş olacaktır, ancak çalışacaktır.

+3

Buna eklemek için, AddRange ile bir toplu bildirimin aksine, her ekleme için bir koleksiyon değişikliği bildirimi de olacaktır. –

0

IEnumerable aralığınızı bir listeye ekleyebilir ve ardından ICollection = listeye ekleyebilirsiniz.

 IEnumerable<T> source; 

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

     ICollection<item> destination = list; 
+3

Bu işlevsel olarak çalışır, ancak Microsoft özelliklerini toplama özelliklerini okumaya zorlar (http://msdn.microsoft.com/en-us/library/ms182327.aspx) –

24

Döngüyü çalıştırmadan önce uzantı yönteminde Listeye döküm yapmayı deneyin. Bu şekilde List.AddRange'un performansından yararlanabilirsiniz. Eğer tek astar istiyorsanız .NET4.5 yana

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

Biraz n00bish soru olabilir ama ne olur ne olur '' '' '' '' '' '' '' '' '' '' '' koleksiyon ''' 'List ' '' 'içine döküm olamaz! '' '' '' '' '' '' '' 'Null'''' otomatik olarak mı yoksa atılan bir istisna mıdır? –

+1

"As" operatörü asla atmayacak. Eğer 'hedef' atanamazsa, 'liste' boş olacak ve 'else' bloğu yürütülecektir. – rymdsmurf

+3

arrgggh! Tüm kutsalların sevgisi için koşul dallarını değiştir! – nicodemus13

15

Eğer can use System.Collections.Generic ForEach.

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

ya da kısa her döngü (sözdizimsel şeker) için aynı şey

source.ForEach(destination.Add); 

Performans açısından olarak.

Ayrıca ForEach geçersizdir

var x = source.ForEach(destination.Add) 

sebep gibi atamadan çalışmayın.

+5

Şahsen bununla ilgili Lippert'im: http://blogs.msdn.com/b/ericlippert/archive /2009/05/18/foreach-vs-foreach.aspx – TrueWill

+1

Kaynak olmalıdır.ForEach (destination.Add)? – Frank

+0

@Frank Merhaba Frank, fark ettiğiniz için teşekkürler sabit :) –