J'ai rencontré un problème étrange et je me demande ce que je devrais faire à ce sujet.Assurez-vous que l'exécution différée ne sera exécutée qu'une seule fois ou sinon
J'ai cette classe qui retourne un IEnumerable<MyClass>
et c'est une exécution différée. En ce moment, il y a deux consommateurs possibles. L'un d'eux trie le résultat.
Voir l'exemple suivant:
public class SomeClass
{
public IEnumerable<MyClass> GetMyStuff(Param givenParam)
{
double culmulativeSum = 0;
return myStuff.Where(...)
.OrderBy(...)
.TakeWhile(o =>
{
bool returnValue = culmulativeSum < givenParam.Maximum;
culmulativeSum += o.SomeNumericValue;
return returnValue;
};
}
}
Les consommateurs appellent l'exécution différée qu'une seule fois, mais si elles devaient l'appeler plus que cela, le résultat serait erroné que le culmulativeSum
ne serait pas remis à zéro. J'ai trouvé le problème par inadvertance avec des tests unitaires. Le moyen le plus simple pour moi de résoudre le problème serait d'ajouter .ToArray()
et de supprimer l'exécution différée au prix d'un peu de temps système.
Je pourrais également ajouter un test unitaire dans la catégorie des consommateurs pour m'assurer qu'ils ne l'appellent qu'une seule fois, mais cela n'empêcherait aucun nouveau consommateur de coder à l'avenir de ce problème potentiel.
Une autre chose qui m'est venue à l'esprit était de faire jeter l'exécution suivante. Quelque chose comme
return myStuff.Where(...)
.OrderBy(...)
.TakeWhile(...)
.ThrowIfExecutedMoreThan(1);
Il est évident que cela n'existe pas. Serait-ce une bonne idée de mettre en œuvre une telle chose et comment le feriez-vous? Sinon, s'il y a un gros éléphant rose que je ne vois pas, le signaler sera apprécié. (Je sens qu'il ya une parce que cette question est d'un scénario très basique: |)
EDIT:
Voici un mauvais exemple d'utilisation des consommateurs:
public class ConsumerClass
{
public void WhatEverMethod()
{
SomeClass some = new SomeClass();
var stuffs = some.GetMyStuff(param);
var nb = stuffs.Count(); //first deferred execution
var firstOne = stuff.First(); //second deferred execution with the culmulativeSum not reset
}
}
Parlez-vous d'une situation où plusieurs threads appellent cette fonction en même temps? Sinon, je ne vois pas comment cela pourrait vous donner un mauvais résultat. culmulativeSum est remis à zéro en haut et il semble être local à la fonction. – JuanR
Voilà pourquoi c'est une mauvaise idée de laisser les méthodes LINQ avoir des effets secondaires. Bien que le code semble simple, ce que vous faites n'est pas vraiment un «scénario de base», et certainement pas un scénario recommandé. – Groo
@Juan: le 'cumulativeSum' est défini sur' 0' chaque fois que vous appelez 'GetMyStuff', mais PAS chaque fois que vous enumerez le résultat. Parce que chaque fois que vous énumérez, vous n'évaluez que la partie LINQ après le 'return'. Par conséquent, chaque heure future que vous énumérez ne récupérera rien car 'cumulativeSum' est déjà plus grand que le maximum. Démonstration: http://ideone.com/VgLbTe. – mellamokb