J'ai pensé que ce serait bien de faire quelque chose comme ça (avec le lambda faisant un retour de rendement):
public IList<T> Find<T>(Expression<Func<T, bool>> expression) where T : class, new()
{
IList<T> list = GetList<T>();
var fun = expression.Compile();
var items = () => {
foreach (var item in list)
if (fun.Invoke(item))
yield return item; // This is not allowed by C#
}
return items.ToList();
}
Cependant, j'ai découvert que je ne peux pas utiliser yield en méthode anonyme. Je me demande pourquoi. Les documents de rendement disent simplement que ce n'est pas autorisé.
Comme ce n'était pas autorisé, je viens de créer une liste et j'y ai ajouté les éléments.
c#
yield
anonymous-methods
yield-return
Lance Fisher
la source
la source
async
lambdas anonymes autorisant l'await
intérieur en C # 5.0, je serais intéressé de savoir pourquoi ils n'ont toujours pas implémenté d'itérateurs anonymes avecyield
inside. Plus ou moins, c'est le même générateur de machine d'état.Réponses:
Eric Lippert a récemment écrit une série d'articles de blog expliquant pourquoi le rendement n'est pas autorisé dans certains cas.
EDIT2:
Vous y trouverez probablement la réponse ...
EDIT1: cela est expliqué dans les commentaires de la partie 5, dans la réponse d'Eric au commentaire d'Abhijeet Patel:
Q:
UNE :
la source
Eric Lippert a écrit une excellente série d'articles sur les limitations (et les décisions de conception influençant ces choix) sur les blocs d'itérateurs
En particulier, les blocs d'itérateur sont implémentés par des transformations de code de compilateur sophistiquées. Ces transformations auraient un impact sur les transformations qui se produisent à l'intérieur des fonctions anonymes ou lambdas de telle sorte que dans certaines circonstances, ils essaieraient tous les deux de «convertir» le code en une autre construction incompatible avec l'autre.
En conséquence, ils sont interdits d'interaction.
Le fonctionnement des blocs d'itérateur sous le capot est bien traité ici .
A titre d'exemple simple d'incompatibilité:
Le compilateur souhaite simultanément convertir ceci en quelque chose comme:
et en même temps, l'aspect itérateur essaie de faire son travail pour créer une petite machine à états. Certains exemples simples peuvent fonctionner avec une bonne quantité de vérification de la cohérence (en traitant d'abord les fermetures imbriquées (éventuellement arbitrairement)) puis en vérifiant si les classes résultantes de niveau inférieur pourraient être transformées en machines à états d'itération.
Cependant ce serait
Dans votre exemple comme ceci:
la source
Magic
classe devrait l'êtreMagic<T>
.Malheureusement, je ne sais pas pourquoi ils n'ont pas permis cela, car il est bien sûr tout à fait possible d'envisager comment cela fonctionnerait.
Cependant, les méthodes anonymes font déjà partie de la "magie du compilateur" dans le sens où la méthode sera extraite soit vers une méthode de la classe existante, soit même vers une toute nouvelle classe, selon qu'elle traite ou non des variables locales.
De plus, les méthodes d'itération utilisant
yield
sont également implémentées à l'aide de la magie du compilateur.Je suppose que l'un de ces deux rend le code non identifiable à l'autre morceau de magie, et qu'il a été décidé de ne pas passer de temps à faire ce travail pour les versions actuelles du compilateur C #. Bien sûr, ce n'est peut-être pas du tout un choix conscient et cela ne fonctionne tout simplement pas parce que personne n'a pensé à le mettre en œuvre.
Pour une question précise à 100%, je vous suggère d'utiliser le site Microsoft Connect et de signaler une question, je suis sûr que vous obtiendrez quelque chose utilisable en retour.
la source
Je ferais ceci:
Bien sûr, vous avez besoin du System.Core.dll référencé à partir de .NET 3.5 pour la méthode Linq. Et incluez:
À votre santé,
Sournois
la source
Peut-être que c'est juste une limitation de syntaxe. Dans Visual Basic .NET, qui est très similaire à C #, il est parfaitement possible, bien que difficile à écrire
Notez également les parenthèses
' here
; la fonction lambdaIterator Function
...End Function
renvoie unIEnumerable(Of Integer)
mais n'est pas un tel objet lui-même. Il doit être appelé pour obtenir cet objet.Le code converti par [1] génère des erreurs dans C # 7.3 (CS0149):
Je ne suis pas du tout d'accord avec la raison donnée dans les autres réponses qu'il est difficile pour le compilateur de gérer. Le que
Iterator Function()
vous voyez dans l'exemple VB.NET est spécialement créé pour les itérateurs lambda.En VB, il y a le
Iterator
mot - clé; il n'a pas d'équivalent C #. À mon humble avis, il n'y a aucune vraie raison pour laquelle ce n'est pas une fonctionnalité de C #.Donc, si vous voulez vraiment, vraiment des fonctions d'itérateur anonymes, utilisez actuellement Visual Basic ou (je ne l'ai pas vérifié) F #, comme indiqué dans un commentaire de la partie 7 dans la réponse de @Thomas Levesque (faites Ctrl + F pour F #).
la source