2008-11-24 8 views
13

Nesneler için LINQ ile çalışıyorum ve bazı durumlarda Aggregate(...) numaralı telefonu aramadan önce temel koleksiyonu değiştirmem ve daha sonra özgün durumuna döndürmem gereken bir işlev var. funciton önce Aggregate(...) sonuçlarını döndürür. Ben koleksiyon değiştirirseniz aggregationResult sayılan ve LINQ önce geri özgün haliyle koleksiyonu atıyorum çünküLINQ çıktısının numaralandırılmasını zorlamak için .ToArray() öğesinden daha iyi bir şey

bool collectionModified = false; 
if(collectionNeedsModification) 
{ 
    modifyCollection(); 
    collectionModified = true; 
} 

var aggregationResult = from a in 
          (from b in collection 
          where b.SatisfysCondition) 
          .Aggregate(aggregationFunction) 
         select a.NeededValue; 

if(collectionModified) 
    modifyCollection(); 

return aggregationResult; 

Ancak yazıldığı gibi, yanlış bir sonuç elde edecek: My geçerli kod şöyle görünür Sonuçlar tembel olarak değerlendirilmiştir. Benim şimdiki çözüm böyle benim LINQ sorgusunda .ToArray() kullanmaktır:

var aggregationResult = (from a in 
          (from b in collection 
          where b.SatisfysCondition) 
          .Aggregate(aggregationFunction) 
         select a.NeededValue).ToArray(); 

çıkan dizinin boyutu her zaman (< 100 öğe) böylece bellek/işlem süresi bir endişe değil küçük olacaktır. Sorunumu çözmenin en iyi yolu bu mu yoksa LINQ sorgusunun değerlendirmesini zorlamak için daha iyi bir yol var mı?

cevap

15

Sadece seni anlıyorum - seni anlamak istiyorum - sadece tüm sonuçlarda yinelemek istiyorsun, sadece yan etkilerin gerçekleşmesini zorlamak için mi? Yan etkiler genellikle kötü bir fikirdir, çünkü bu tür bir mantıkla olayları anlamak daha zordur. Tam bir değerlendirme yapmak ve zorlamak için en kolay yolu sadece yinelemenize muhtemelen, söyledikten:

foreach (var result in aggregationResult) 
{ 
    // Deliberately empty; simply forcing evaluation of the sequence. 
} 

Alternatif ToArray yer alan bütün kopyalama() önlemek için LastOrDefault() kullanabilirsiniz. Sonuç IList<T> uygulanmadığı sürece (kısa bir kesmeyi içeren) Count() tamamdır.

+2

tercihim '.LastOrDefault()'. 'LastOrDefault' ayrıca kısa bir yol alır (benim versiyonumda .NET 4.5.2).Kaynak bir "IList <>" ise, önce "Count" değerini alır ve sonra indeksleyiciyi "Count - 1" indeksi ile almak için kullanır. Örneğin bu çalışma (Moq kullanır): 'var listMock = yeni Mock > (MockBehavior.Strict); listMock.Setup (x => x.Count) .Returns (666); listMock.Setup (x => x [665]). Döndürür ("sonuncu"); var last = listMock.Object.LastOrDefault(); ' –

0

Eğer her zaman sonucu kullanırsanız (sonuç kümenizin büyük olmaması nedeniyle çok fazla bellek tüketmeyeceğinden) yaklaşımınız ile ilgili bir sorun olduğunu düşünmüyorum. asla sonucu kullanmayın, bir performans kaybı empoze eder). Evet, bu, bunu yapmanın doğru yolu.

3

Yukarıdaki changeCollection gibi yan etki işlevlerinden kaçınmak daha iyidir.

Daha iyi bir yaklaşım, değiştirilmiş koleksiyonu (veya sorguyu) döndüren ve ilkini sağlam bırakan bir işlev yapmaktır. ModifyCollection collectionNeedsModification Boole parametresine bağlı parametre modifiye toplama (veya sorgu) döndüren bir yöntemdir

var modifiedCollection = ModifyCollection(collection, collectionNeedsModification); 

var aggregationResult = from a in 
         (from b in modifiedCollection 
         where b.SatisfysCondition) 
         .Aggregate(aggregationFunction) 
        select a.NeededValue; 

.

12

(Not: Kod denenmemiş yani el altında bir derleyici olmadan yazarak,):

aggregationResult.Run(); 

sen çalıştır seçeneğini kullanabilirsiniz zaten bağımlılık() olarak .NET için Reaktif Extensions varsa

Ancak bunun için bir bağımlılık eklememize gerek olmayabilir.

Ayrıca bir uzantısı yöntemi olarak çalıştır yöntemini kendiniz uygulayabilir:

public static MyLinqExtensions 
{ 
    public static void Run<T>(this IEnumerable<T> e) 
    { 
     foreach (var _ in e); 
    } 
} 
+0

Sayım, 'canlı' (RX'de olduğu gibi) veya soruya yanıt olarak iyi olduğunda bu iyi olabilir. Ama genel kullanım için değil, tembel tempolu olmadığından emin olmak gerektiğinde, sanırım "LastOrDefault" - kısa yol alır - daha iyidir. –