2011-01-07 36 views
7

Bir d verildiğinde, bir liste veya dizi gibi sabit bir diziyle, bazı dış veri kaynağını veya bazı mevcut koleksiyonlarda AST'yi numaralandıracak bir AST ile ilgileniyor olabilirsiniz. Numaralandırılabilir şekilde güvenli bir şekilde "materyalize etmek" için bir yol var mıdır, böylece foreach, count, vb. Gibi numaralandırma işlemleri her seferinde AST'yi uygulamaz mı?Bir IEnumerable ezberlemek veya Materialize için bir yolu var mı?

Bu temsili oluşturmak için sık sık .ToArray() kullanıyorum ancak temel depolama alanı zaten bir liste veya başka bir sabit dizilimse, boşa harcanan kopya gibi görünüyor. i .Any() ve foreach iki kez ve unccessarily enumerable kopyalamadan diziyi numaralandırmak deneyin endişe duymadan

var enumerable = someEnumerable.Materialize(); 

if(enumberable.Any() { 
    foreach(var item in enumerable) { 
    ... 
    } 
} else { 
    ... 
} 

yapıp yapamayacağımı iyi olurdu.

+1

Bu güzel bir fikir, ancak mevcut koleksiyona karşı mutasyonlara karşı korumak için mevcutCollection.ToList öğesinin yapıldığını belirtmek isterim. – Ani

+0

.ToList() ile ilgili sorun, listelenmemiş (diziler, ICollections, vb.) Bir numaralar listesi oluşturacak ve değiştirilebilen bir koleksiyon döndürecektir. –

cevap

6

Kolay:

sadece biraz daha iyi bana göre Thomas'ın cevap olarak
public static IList<TSource> Materialize<TSource>(this IEnumerable<TSource> source) 
{ 
    if (source is IList<TSource>) 
    { 
     // Already a list, use it as is 
     return (IList<TSource>)source; 
    } 
    else 
    { 
     // Not a list, materialize it to a list 
     return source.ToList(); 
    } 
} 
+3

Bu iyi bir yaklaşım. Bunun yerine bir IEnumerable 'döndürmek ve" ICollection "ve" ICollection "için de kontrol etmek daha iyi olurdu. – Ani

+4

Bu, Linq.ToList() uygulamasından her zaman yeni bir kopyasını iade etmek için görünen sonuçtan farklıdır, böylece sonuçtaki değişiklikler orijinali değiştirmez. Yazılı olarak biçimlendirmek, giriş türüne bağlı olarak bazen bir kopyasını iade eder ve bazen orijinali döndürür - böylece sonuçtaki değişiklikler bazen orijinali değiştirir. – Handcraftsman

+0

Ani doğru fikre sahip. Niyetim, sadece bir 'IEnumerable ', birden çok kez numaralandırmak için güvenli ve verimli bir değiştirilebilir liste oluşturmak değil. Ayrıca, hiç test etmemişken, ToArray() 'ın daha ucuz geri dönüş materyalizer olduğunu varsayalım. –

2

Kontrol blog postasına Ben birkaç yıl önce yazdığım: http://www.fallingcanbedeadly.com/posts/crazy-extention-methods-tolazylist/

İçinde ben etkili bir şekilde aradığınızı yapan bir yöntemi denir ToLazyList tanımlar.

Yazdığı gibi, giriş dizisinin tam bir kopyasını oluşturacaktır, ancak IList örneklerinin bir LazyList'e sarılmaması, bunun olmasını engelleyecektir. aldığınız herhangi bir IList'in zaten etkili bir şekilde anıldığı varsayımını taşıyacaktır). Yeterince

+1

Bu gerçekten ilginç bir eklentidir, ancak OP'nin istediği şeyle ilgili olduğunu sanmıyorum. Bu, * sıranın ihtiyaç bazında gerçekleşmesini * önler; oysa OP, istekli bir şekilde * sırasını verimli bir şekilde materyalize eder; Gerekirse var olan bir koleksiyona başvuru almak. – Ani

+0

Blogunuzda bir şey bozuldu gibi görünüyor. Bu yazıda bulunan 'www' eksik olan site köküne yeniden yönlendirildi –

6

aynı:

public static ICollection<T> Materialize<T>(this IEnumerable<T> source) 
{ 
    if (source == null) 
     return null; 

    return source as ICollection<T> ?? source.ToList(); 
} 

bu mevcut koleksiyonu kendisi geri dönme eğiliminde olduğuna dikkat edin onun geçerli bir koleksiyon halinde aksi halde yazın veya yeni bir koleksiyon üretir. İki kurnazca farklı olsa da, bir sorun olabileceğini düşünmüyorum.

İlgili konular