2010-02-03 13 views
8

Sto pensando a un rifacimento, ma non so se il risultato finale è semplicemente eccessivo. Attualmente hoSta usando linq in questa situazione overkill

IList<myobjecttypebase> m_items; 

    public int GetIncrementTotal() 
    { 
    int incrementTot; 
    foreach(myobjecttypebase x in m_items) 
    { incrementTot += x.GetIncrement(); } 
    } 

sarebbe eccessivo e/o meno efficiente di utilizzare LINQ per la PerOgni

m_items.ToList().ForEach(x => incrementTot += x.GetIncrement()); 

Sarebbe il cast essere un notevole sovraccarico qui?

risposta

4

Il metodo ToList è un metodo di estensione utilizzato con LINQ, ma il metodo ForEach è solo un metodo di nella classe List.

L'overhead principale qui è la chiamata al metodo ToList, che crea una nuova lista dalla raccolta. Anche ForEach ha un leggero sovraccarico in quanto deve chiamare un delegato per ogni articolo.

Se si desidera utilizzare i metodi di LINQ, il metodo aggregato sembra più appropriato:

public int GetIncrementTotal() { 
    return m_items.Aggregate(0, (t, i) => t + i.GetIncrement()); 
} 

O Somma:

public int GetIncrementTotal() { 
    return m_items.Sum(i => i.GetIncrement()); 
} 

o ha un piccolo sovraccarico, sopra la versione originale, quindi se si vuole il più efficiente, limitati a un semplice ciclo.

+0

Grazie per la risposta completa Guffa. – Andrew

+0

Il "leggero sovraccarico" qui è solo la differenza tra chiamare un delegato e un codice inline. A meno che la raccolta non sia enorme, o se si sommano molte raccolte che utilizzano questa base come base per le scelte di codifica, rientra nell'area dell'ottimizzazione prematura. Apporta modifiche come questa solo se il test delle prestazioni mostra un miglioramento significativo rispetto al tempo di esecuzione totale. – Richard

3

Il sovraccarico verrà ripetuto per due volte nella raccolta.

m_items.ToList() // First iteration to add to the list all the items 
    .ForEach(x => incrementTot += x.GetIncrement()); /* Second iteration to 
                 perform logic */ 

ToList non esegue l'iterazione in maniera artificiale come la maggior parte dichiarazioni LINQ, per esso forzerà il codice iterate sulla raccolta due volte.

In generale, il modulo LINQ sembra più piacevole da leggere, ma se ti preoccupi delle prestazioni, è meglio evitarlo.

+0

Suppongo che la versione di linq sia quella con il sovraccarico. In caso affermativo, perché il metodo ToList() deve iterare l'enumerazione per eseguire il cast da un IList – Andrew

+0

@Andrew - Perché è necessario convertire la raccolta in un elenco . – Oded

+0

@Andrew: il metodo ToList() non è un cast. È un metodo di conversione e assegnerà e popolerà un nuovo oggetto List <>. –

7

Perché non utilizzare l'operatore SUM direttamente su IList?

Essa ha diversi overload utilizzando Func delegati:

m_items.Sum(x => x.GetIncrement()); 
+0

il metodo GetIncrement è un metodo astratto sulla classe base e diverse implementazioni concrete sovrascrivono il valore dell'incremento. Altrimenti avrei appena usato .Count() sul IList – Andrew

+0

Non cambia la risposta ... – Oded

+0

Vedo il tuo punto grazie all'esempio di codice di John qui sotto. – Andrew

1

Non farlo in questo modo.
Il ToList() qui assegnerà e popolerà un nuovo elenco, IMHO non necessario. Mentre è un esercizio banale scrivere un metodo di estensione ForEach per iterare su qualsiasi oggetto che implementa IEnumberable, sconsiglio di farlo (vedi questo articolo di Eric Lippert foreach V's ForEach).

Vorrei andare con il foreach.

P.S. è necessario inizializzare incrementTot (mi dispiace, non ho potuto farne a meno)

2

Come accennato Oded uso SUM

incrementTot = m_items.ToList().Sum(x => x.GetIncrement()); 
+2

Perché preoccuparsi di creare un elenco se tutto ciò che si sta per fare è sommare i valori? –

+0

Grazie per l'esempio. Non ho capito cosa intendesse Oded perché sono relativamente nuovo a linq. – Andrew

+0

Jon skeet è giusto per una volta. ToList è superfluo. –

3

ForEach non è parte di LINQ - è parte del List<T> API ed è stato da allora. NET 2.0.

La ragione per cui non fa parte di LINQ è che si tratta di un metodo naturalmente a effetto collaterale ... e LINQ non incoraggia gli effetti collaterali.

Utilizzando somma è la soluzione giusta qui, ma non è necessario per creare una lista prima:

return m_items.Sum(x => x.GetIncrement()); 
Problemi correlati