2010-02-03 7 views
8

Je pense à un nouveau facteur, mais je ne sais pas si le résultat final est tout simplement surpuissant. Actuellement, j'aiEst-LINQ dans cette situation surpuissance

IList<myobjecttypebase> m_items; 

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

Serait-il exagéré et/ou moins efficace d'utiliser LINQ pour le ForEach

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

Est-ce que le casting est une surcharge importante ici?

Répondre

4

La méthode ToList est une méthode d'extension utilisé avec LINQ, mais la méthode ForEach est juste une méthode dans la classe List.

Le grand frais généraux est ici l'appel à la méthode ToList, ce qui crée une nouvelle liste de la collection. Le ForEach a également une légère surcharge, car il doit appeler un délégué pour chaque élément.

Si vous voulez utiliser des méthodes LINQ, la méthode globale semble plus approprié:

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

Ou Somme:

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

Soit a une légère surcharge sur votre version originale, donc si vous voulez le plus efficace, il suffit de s'en tenir à une simple boucle.

+0

Merci pour la réponse complète Guffa. – Andrew

+0

La "légère surcharge" ici est juste la différence entre l'appel d'un délégué et le code en ligne. À moins que la collection soit énorme, ou que vous additionniez beaucoup de collections en utilisant ceci comme base pour les choix de codage tombe dans le domaine de l'optimisation prématurée. N'apportez des modifications de ce type que si les tests de performances montrent que vous obtiendrez une amélioration significative de votre temps d'exécution total. – Richard

3

Le surdébit sera d'itérer deux fois la collection.

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

ToList ne fonctionne pas l'itération de manière paresseuse comme la plupart des déclarations LINQ, à cet effet, il forcera le itérer de code sur la collection deux fois.

En général, la forme LINQ semble plus agréable à lire, mais si vous soucier de la performance que vous évitez mieux ce.

+0

Je suppose que la version linq serait celle avec le surdébit. Si oui, pourquoi la méthode ToList() aurait-elle besoin d'itérer l'énumération sur une liste IList? – Andrew

+0

@Andrew - Parce qu'elle doit convertir la collection en liste . – Oded

+0

@Andrew: La méthode ToList() n'est pas un cast. C'est une méthode de conversion qui alloue et remplit un nouvel objet List <>. –

7

Pourquoi ne pas utiliser l'opérateur SUM directement sur le IList?

Il ne plusieurs délégués Func en utilisant les surcharges:

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

La méthode GetIncrement est une méthode abstraite de la classe de base et différentes implémentations concrètes remplacent la valeur de l'incrément. Sinon j'aurais juste utilisé .Count() sur le IList – Andrew

+0

Ne change pas la réponse ... – Oded

+0

Je vois votre point de vue grâce à l'exemple de code de John ci-dessous. – Andrew

1

Ne pas le faire de cette façon.
Le ToList() va ici allouer et remplir une nouvelle liste, à mon humble avis pas nécessaire. Bien qu'il soit un exercice trivial d'écrire une méthode d'extension foreach pour itérer sur un objet qui implémente IEnumberable, je vous conseille contre (voir cet article par Eric Lippert foreach V's ForEach).

J'irais avec le foreach.

P.S. vous devez incrementTot initialiser (désolé, je ne pouvais pas aider moi-même)

2

Comme Oded mentionné l'utilisation SUM

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

Pourquoi s'embêter à créer une liste si tout ce que vous allez faire, c'est additionner les valeurs? –

+0

Merci pour l'exemple. Je n'ai pas compris ce qu'Oded voulait dire car je suis relativement nouveau à linq. – Andrew

+0

Jon Skeet est juste pour une fois. ToList est superflu. –

3

ForEach ne fait pas partie de LINQ - il fait partie de l'API List<T> et a été depuis. NET 2.0.

La raison pour laquelle il ne fait pas partie de LINQ est que c'est une méthode naturellement ... effectuer côté et LINQ ne favorise pas les effets secondaires.

Utiliser Somme est la solution ici, mais vous n'avez pas besoin de créer une première liste:

return m_items.Sum(x => x.GetIncrement()); 
Questions connexes