Impossible d’utiliser le paramètre ref ou out dans les expressions lambda

Pourquoi ne pouvez-vous pas utiliser un paramètre ref ou out dans une expression lambda?

Je suis tombé sur l’erreur aujourd’hui et j’ai trouvé une solution de contournement, mais j’étais toujours curieux de savoir pourquoi il s’agissait d’une erreur de compilation.

CS1628 : Impossible d’utiliser dans le paramètre ref ou out ‘paramètre’ dans une méthode anonyme, une expression lambda ou une expression de requête

Voici un exemple simple:

private void Foo() { int value; Bar(out value); } private void Bar(out int value) { value = 3; int[] array = { 1, 2, 3, 4, 5 }; int newValue = array.Where(a => a == value).First(); } 

Les Lambdas ont l’apparence de changer la durée de vie des variables qu’ils capturent. Par exemple, l’expression lambda suivante fait en sorte que le paramètre p1 dure plus longtemps que le cadre de la méthode actuelle, car sa valeur est accessible après que le cadre de la méthode n’est plus sur la stack.

 Func Example(int p1) { return () => p1; } 

Une autre propriété des variables capturées est que les modifications apscopes à la variable sont également visibles en dehors de l’expression lambda. Par exemple les impressions suivantes 42

 void Example2(int p1) { Action del = () => { p1 = 42; } del(); Console.WriteLine(p1); } 

Ces deux propriétés produisent un certain ensemble d’effets qui se heurtent à un paramètre ref de la manière suivante:

  • Les parameters ref peuvent avoir une durée de vie fixe. Pensez à transmettre une variable locale comme paramètre ref à une fonction.
  • Les effets secondaires dans le lambda doivent être visibles sur le paramètre ref lui-même. Tant dans la méthode que dans l’appelant.

Ce sont des propriétés quelque peu incompatibles et l’une des raisons pour lesquelles elles sont interdites dans les expressions lambda.

Sous le capot, la méthode anonyme est implémentée en soulevant les variables capturées (ce qui concerne tout le corps de votre question) et en les stockant en tant que champs d’une classe générée par le compilateur. Il est impossible de stocker un paramètre ref ou out tant que champ. Eric Lippert en a parlé dans une entrée de blog . Notez qu’il existe une différence entre les variables capturées et les parameters lambda. Vous pouvez avoir des “parameters formels” comme les suivants car ils ne sont pas des variables capturées:

 delegate void TestDelegate (out int x); static void Main(ssortingng[] args) { TestDelegate testDel = (out int x) => { x = 10; }; int p; testDel(out p); Console.WriteLine(p); } 

Vous pouvez mais vous devez définir explicitement tous les types afin

 (a, b, c, ref d) => {...} 

Est invalide, cependant

 (int a, int b, int c, ref int d) => {...} 

Est valable

Comme c’est l’un des meilleurs résultats pour “C # lambda ref” sur Google; Je pense que je dois développer les réponses ci-dessus. L’ancienne syntaxe de délégué anonyme (C # 2.0) fonctionne et prend en charge des signatures plus complexes (ainsi que des fermetures). Les delegates Lambda et anonymes ont pour le moins partagé l’implémentation perçue dans le backend du compilateur (s’ils ne sont pas identiques) – et surtout, ils supportent les fermetures.

Ce que j’essayais de faire quand j’ai fait la recherche, pour démontrer la syntaxe:

 public static ScanOperation CreateScanOperation( PrattTokenDefinition tokenDefinition) { var oldScanOperation = tokenDefinition.ScanOperation; // Closures still work. return delegate(ssortingng text, ref int position, ref PositionInformation currentPosition) { var token = oldScanOperation(text, ref position, ref currentPosition); if (token == null) return null; if (tokenDefinition.LeftDenotation != null) token._led = tokenDefinition.LeftDenotation(token); if (tokenDefinition.NullDenotation != null) token._nud = tokenDefinition.NullDenotation(token); token.Identifier = tokenDefinition.Identifier; token.LeftBindingPower = tokenDefinition.LeftBindingPower; token.OnInitialize(); return token; }; } 

Gardez à l’esprit que les Lambdas sont plus sûrs sur le plan procédural et mathématique (en raison de la promotion de la valeur ref mentionnée précédemment): vous pouvez ouvrir une boîte de Pandore. Réfléchissez bien lorsque vous utilisez cette syntaxe.