Peuvent tous être "pour" boucles d'être remplacé par un LINQ déclaration?
Est-il possible d'écrire le "foreach" comme LINQ déclaration, et je pense que la question plus générale peut tout de boucle pour être remplacé par un LINQ déclaration.
Je ne suis pas intéressé par un quelconque potentiel de performance des coûts tout le potentiel de l'utilisation déclarative approches dans ce qui est traditionnellement code impératif.
private static string SomeMethod()
{
if (ListOfResources .Count == 0)
return string.Empty;
var sb = new StringBuilder();
foreach (var resource in ListOfResources )
{
if (sb.Length != 0)
sb.Append(", ");
sb.Append(resource.Id);
}
return sb.ToString();
}
Acclamations
AWC
Vous devez vous connecter pour publier un commentaire.
Sûr. Heck, vous pouvez remplacer arithmétique avec des requêtes LINQ:
http://blogs.msdn.com/ericlippert/archive/2009/12/07/query-transformations-are-syntactic.aspx
Mais vous ne devriez pas.
Le but d'une expression de requête est de représentent une opération de requête. Le but d'une boucle "for" est d'itérer sur une instruction particulière, de façon à avoir ses effets secondaires exécutée plusieurs fois. Ceux-ci sont souvent très différents. J'encourage le remplacement des boucles dont le but est simplement de requête de données de haut niveau ainsi que des constructions plus clairement des requêtes sur les données. Je déconseille vivement de remplacer des effets secondaires de la génération de code avec des interprétations de la requête, si cela est possible.
for
boucles d'interrogation comme des extensions, sont les suivants: 1) évaluation différée des effets secondaires à la consommation de site de, et 2) la conversion de la boucle en constructions fonctionnelles pour l'évaluation parallèle (comme dans PLINQ). Il est difficile de réaliser soit normale avec une boucle.En général oui, mais il y a des cas particuliers qui sont extrêmement difficiles. Par exemple, le code suivant dans le cas général n'a pas de port pour une expression LINQ sans une bonne affaire de piratage.
La raison en est que, avec une boucle for, il est possible de voir les effets secondaires de la façon dont la variable d'itération est capturé par une fermeture. Les expressions LINQ cacher la durée de vie de la sémantique de la variable d'itération et de vous empêcher de voir les effets secondaires de la capture de la valeur.
Note. Le code ci-dessus est pas équivalent à celui-ci expression LINQ.
Le foreach exemple produit une liste de
Func<int>
objets qui reviennent tous les 3. Le LINQ version produit une liste deFunc<int>
de retour 1,2 et 3 respectivement. C'est ce qui rend ce style de capture difficile de port.Func<int>
qui reviennent tous les 3. Le vôtre sera de retour 1,2 et 3.En fait, votre code n'quelque chose qui est fondamentalement très fonctionnelle, à savoir qu'il réduit une liste de chaînes de caractères d'une chaîne unique en concaténant les éléments de la liste. Le seul impératif chose à propos de ce code est l'utilisation d'un
StringBuilder
.Le code fonctionnel cela rend beaucoup plus facile, en fait, car il n'a pas besoin d'un cas comme le votre code ne. Mieux encore, .NET déjà a cette opération mise en œuvre, et sans doute plus efficace que votre code1):
(Oui, l'appel à
ToArray()
est ennuyeux, maisJoin
est une très ancienne méthode et est antérieure à LINQ.)Bien sûr, une “meilleure” version de
Join
pourrait être utilisée comme ceci:La mise en œuvre est assez simple – mais encore une fois, à l'aide de la
StringBuilder
(pour la performance), il est impératif.1) Sans avoir regardé la mise en œuvre dans le réflecteur, je suppose que
String.Join
fait un premier passage sur les cordes afin de déterminer la longueur totale. Cela peut être utilisé pour initialiser laStringBuilder
en conséquence, sauvant ainsi de coûteuses opérations de copie plus tard.ÉDITION par SLaks: Ici est la source de référence pour la partie pertinente de
String.Join
de .Net 3.5:String.Join
prend également un IEnumerable 🙂char[]
avec certains internes dangereux copie des astuces pour atteindre des performances encore meilleures.La boucle spécifique dans votre question peut être fait de manière déclarative comme ceci:
De performance, vous pouvez vous attendre à une chute des performances, mais c'est acceptable pour la plupart des applications.
Je pense que le plus important ici est que, pour éviter la confusion sémantique, votre code ne doit être superficiellement fonctionnel lorsqu'il est fait fonctionnelle. En d'autres termes, veuillez ne pas utiliser d'effets secondaires dans les expressions LINQ.
Techniquement, oui.
Tout
foreach
boucle peut être converti à LINQ à l'aide d'unForEach
méthode d'extension,tels que celui de MoreLinq.Si vous souhaitez uniquement utiliser "pure" de LINQ (seulement intégré dans les méthodes d'extension), vous pouvez abuser de la
Aggregate
méthode d'extension, comme ceci:Cela permettra de gérer correctement les tout boucle foreach, même JaredPar de réponse. MODIFIER: à Moins qu'il utilise
ref
/out
paramètres, le code unsafe, ouyield return
.N'avez-vous pas ose utiliser cette astuce dans le code réel.
Dans votre cas particulier, vous devez utiliser une chaîne
Join
méthode d'extension, comme celui-ci:En général, vous pouvez écrire une expression lambda à l'aide d'un délégué qui représente le corps d'un foreach cycle, dans votre cas, quelque chose comme :
et puis il suffit d'utiliser dans un ForEach de la méthode d'extension. Si c'est une bonne idée dépend de la complexité de l'organisme, dans le cas où il est trop gros et trop complexe, vous n'aurez probablement pas obtenir quelque chose de lui, sauf pour la confusion possible 😉