Fonction locale vs Lambda C # 7.0

Je regarde les nouvelles implémentations de C # 7.0 et je trouve intéressant qu’elles aient implémenté des fonctions locales mais je ne peux pas imaginer un scénario où une fonction locale serait préférée à une expression lambda, et quelle est la différence entre les deux.

Je comprends que les lambdas sont anonymous fonctions anonymous alors que les fonctions locales ne le sont pas, mais je ne peux pas comprendre un scénario réel, où la fonction locale a des avantages sur les expressions lambda

Tout exemple serait très apprécié. Merci.

Cela a été expliqué par Mads Torgersen dans C # Design Meeting Notes où les fonctions locales ont été abordées pour la première fois :

Vous voulez une fonction d’assistance. Vous ne l’utilisez que dans une seule fonction, et il utilise probablement des variables et des parameters de type qui sont dans la scope de cette fonction. Par contre, contrairement à un lambda, vous n’en avez pas besoin en tant qu’object de première classe, vous ne voulez donc pas lui atsortingbuer un type de délégué et allouer un object délégué réel. Vous pouvez également souhaiter qu’il soit récursif ou générique, ou l’implémenter en tant qu’iterator.

Pour en savoir plus, les avantages sont les suivants:

  1. Performance.

    Lors de la création d’un lambda, un délégué doit être créé, ce qui constitue une allocation inutile dans ce cas. Les fonctions locales ne sont que des fonctions, aucun délégué n’est nécessaire.

    En outre, les fonctions locales sont plus efficaces pour capturer les variables locales: les lambdas capturent généralement les variables dans une classe, tandis que les fonctions locales peuvent utiliser une structure (passée avec ref ), ce qui évite encore une allocation.

    Cela signifie également que l’appel des fonctions locales est moins coûteux et qu’elles peuvent être intégrées, ce qui peut même augmenter les performances.

  2. Les fonctions locales peuvent être récursives.

    Lambdas peut aussi être récursif, mais il nécessite un code maladroit, dans lequel vous commencez par atsortingbuer la valeur null à une variable déléguée puis à la lambda. Les fonctions locales peuvent naturellement être récursives (y compris mutuellement récursives).

  3. Les fonctions locales peuvent être génériques.

    Les Lambdas ne peuvent pas être génériques, car ils doivent être affectés à une variable de type concret (ce type peut utiliser des variables génériques de la scope externe, mais ce n’est pas la même chose).

  4. Les fonctions locales peuvent être implémentées comme un iterator.

    Lambdas ne peut pas utiliser le mot clé yield return (et yield break ) pour implémenter la fonction de retour IEnumerable . Les fonctions locales peuvent.

  5. Les fonctions locales ont l’air mieux.

    Ceci n’est pas mentionné dans la citation ci-dessus et pourrait être juste mon parti pris personnel, mais je pense que la syntaxe de la fonction normale semble meilleure que d’atsortingbuer un lambda à une variable délégué. Les fonctions locales sont également plus succinctes.

    Comparer:

     int add(int x, int y) => x + y; Func add = (x, y) => x + y; 

En plus de l’excellente réponse de svick, il y a un autre avantage aux fonctions locales:
Ils peuvent être définis n’importe où dans la fonction, même après la déclaration de return .

 public double DoMath(double a, double b) { var resultA = f(a); var resultB = f(b); return resultA + resultB; double f(double x) => 5 * x + 3; } 

Je suis surpris que personne n’ait mentionné que les fonctions locales ne créent pas de fermetures => pas de variables copiées par valeur dans la fonction, elles fonctionnent comme des parameters ref (ce qui est un avantage incroyable!)

Si vous incrémentez int i dans la fonction locale, vous l’incrémentez également en dehors de cette fonction, avec lambdas vous n’incrémentez que votre copie locale à l’intérieur.

J’utilise des fonctions en ligne pour éviter la pression de la collecte des ordures, en particulier lorsque des méthodes de fonctionnement plus longues sont utilisées. Supposons que l’on souhaite obtenir 2 ans ou des données de marché pour un symbole boursier donné. En outre, il est possible d’emballer beaucoup de fonctionnalités et de logique métier si nécessaire.

ce que l’on fait c’est ouvrir une connexion socket au serveur et faire une boucle sur les données liant un événement à un événement. On peut penser à la manière dont une classe est conçue, mais un seul n’est pas en train d’écrire des méthodes d’aide partout qui ne fonctionnent que pour une seule fonctionnalité. ci-dessous est un exemple de la façon dont cela pourrait ressembler, s’il vous plaît noter que je suis en utilisant des variables et les méthodes “helper” sont en dessous de la finale. En fin de compte, je supprime bien les gestionnaires d’événements, si ma classe Exchange serait externe / injectée, aucun gestionnaire d’événements en attente ne serait enregistré

 void List RequestData(Ticker ticker, TimeSpan timeout) { var socket= new Exchange(ticker); bool done=false; socket.OnData += _onData; socket.OnDone += _onDone; var request= NextRequestNr(); var result = new List(); var start= DateTime.Now; socket.RequestHistoricalData(requestId:request:days:1); try { while(!done) { //stop when take to long…. if((DateTime.Now-start)>timeout) break; } return result; }finally { socket.OnData-=_onData; socket.OnDone-= _onDone; } void _OnData(object sender, HistoricalData data) { _result.Add(data); } void _onDone(object sender, EndEventArgs args) { if(args.ReqId==request ) done=true; } } 

Vous pouvez voir les avantages mentionnés ci-dessous, ici vous pouvez voir un exemple d’implémentation. J’espère que ça aide à expliquer les avantages.