Quelle est la scope d’une variable lambda en C #?

Je suis confus quant à la scope de la variable lambda, prenons par exemple ce qui suit

var query = from customer in clist from order in olist .Where(o => o.CustomerID == customer.CustomerID && o.OrderDate == // line 1 olist.Where(o1 => o1.CustomerID == customer.CustomerID) // line 2 .Max(o1 => o1.OrderDate) // line 3 ) select new { customer.CustomerID, customer.Name, customer.Address, order.Product, order.OrderDate }; 

Dans la ligne 1, j’ai déclaré une variable lambda ‘o’, ce qui signifie que je ne peux pas le déclarer à nouveau dans la ligne 2 (ou au moins le compilateur se plaint si j’essaye) Mais il ne se plaint pas de la ligne 3 ??

Quelle est la scope d’une variable lambda?

Les parenthèses donnent l’indice – la variable lambda est capturée dans le cadre de l’endroit où elle est déclarée:

 .Where(o => ... olist.Where(o1 => ...).Max(o1 => ...)) // |----------------------------------------------| scope of o // |---------| scope of first o1 // |---------| scope of second o1 

Notez qu’il n’y a pas de chevauchement pour les deux variables o1 , mais elles chevauchent (ou masquent) la variable o et ne peuvent donc pas utiliser le même nom.

La scope d’un paramètre lambda est égale à la scope entière du corps de l’expression lambda, y compris les expressions ou scopes lambda internes.

Si nous développons la syntaxe de vos expressions lambda et y ajoutons une indentation amicale, cela peut devenir plus clair (bien que ce soit sans doute aussi clair que la réponse schématique de yamen !):

 .Where(o => { return o.CustomerID == customer.CustomerID && o.OrderDate == olist.Where( o1 => o1.CustomerID == customer.CustomerID ) .Max( o1 => o1.OrderDate ); }) 

Notez que votre .Where().Max() est situé dans un .Where() externe. L’ o dans le lambda externe est encapsulé par le lambda externe dans votre lambdas interne (cela s’appelle la fermeture ) de telle sorte qu’il existe déjà dans la scope de votre lambdas interne, et ne peut pas être réutilisé comme paramètre.

Vous pouvez réutiliser o1 parce que vos deux lambda internes sont complètement séparés l’un de l’autre, de sorte qu’il ne dépasse pas le cadre de l’un ou l’autre.

Vous ne pouvez pas utiliser le même nom de variable dans deux scopes si l’une des scopes contient l’autre.

Dans votre question, o est introduit dans la scope externe, il ne peut donc plus être utilisé dans la deuxième Where() ou Max() , car ces scopes sont contenues dans la zone externe.

D’autre part, vous pouvez utiliser o1 dans les deux scopes internes car l’une ne contient pas l’autre, il n’y a donc aucune ambiguïté.

parce que lamda est le remplacement de la fonction anonyme ici dans votre code

Même scope

 Where(o => o.CustomerID == customer.CustomerID && o.OrderDate == //line 1 olist.Where(o1 => o1.CustomerID == customer.CustomerID) //line 2 

est la scope de la fonction dans laquelle varialble “o” vivre

ici en ligne trois c’est nouveau scrop de la variable ie nouvelle scope de la fonction

Portée différente

  .Max(o1 => o1.OrderDate) ) //line 3 

de sorte que la reson dans line1 et line2 varialbe “o” défini dans line1 ne peut pas être défini dans line2 à cause du même scrop et que “o1” définit dans line2 peut être défini à nouveau dans line3

C # ne supporte pas l’observation comme ça.

La raison pour laquelle o1 fonctionne à nouveau, est que cela ne fait pas fi du précédent o1 .

C’est la même chose que pour toute autre variable. La scope de o est l’expression entière de votre premier Where , vous ne pouvez donc plus l’utiliser dans la seconde, qui est à l’intérieur du premier. Mais la scope de o1 est juste l’expression de votre deuxième Where , vous pouvez donc l’utiliser dans l’expression de votre Max , qui est en dehors du second Where . Dans le code:

 // o scope lasts until the first bracket is closed Where(o => o.CustomerID == customer.CustomerID && o.OrderDate == // o1 scope lasts until the second bracket is closed; the first is not yet closed here olist.Where(o1 => o1.CustomerID == customer.CustomerID) // The second bracket is closed, so o1 is already out of scope; o is still in scope .Max(o1 => o1.OrderDate) ) // The first bracket is closed, so o is finally out of scope 

J’essaie de la photo comme ceci selon votre code …

 .Where(o => o.CustomerID == customer.CustomerID && o.OrderDate == // line 1 olist.Where(o1 => o1.CustomerID == customer.CustomerID) // line 2 .Max(o1 => o1.OrderDate) // line 3 ) 

Manière assez grossière d’expliquer mais vos parenthèses déterminent la scope. Votre 2ème o1 n’est pas nested dans la seconde où, autrement, vous auriez le même problème

 //outermost where ((BEGIN-o //inner where (BEGIN-o1 END-o1) //max (BEGIN-o1 END-o1) END-o)) 
 var external = 1; //This is a scope Action scope = new Action(() => { //myVar is not accessible from outside var myVar = 0 + external; Console.WriteLine(myVar); //outputs 1 }); //Call the scope scope(); //Console.WriteLine(myVar);//Will not comstack 

Lorsque le code est compilé, toute la logique du vide déclaré dans l’action ()=>{ ... } sera déplacée vers une méthode du type avec un nom tronqué.

Le temps d’exécution appellera la fonction nouvellement créée lorsqu’elle atteindra cet endroit sur la stack.

Vous pouvez transmettre des valeurs dans une scope / lambda de différentes manières, ce qui est la même chose pour les extraire.

Les variables déclarées dans un lambda ne sont pas accessibles à l’extérieur avec leur nom déclaré.

Il est également possible d’utiliser la reflection pour retirer le nom déchiqueté, mais je ne suis pas sûr que vous en ayez besoin. (S’il vous plaît laissez-moi savoir si je me trompe.)