Frage

Ich fand das folgende ziemlich seltsame. Andererseits habe ich hauptsächlich Verschlüsse in dynamischen Sprachen verwendet, die demselben "Fehler" nicht verdächtigt werden sollten. Das Folgende macht den Compiler unglücklich:

VoidFunction t = delegate { int i = 0; };

int i = 1;

Es sagt:

Eine lokale Variable namens 'I' kann in diesem Bereich nicht deklariert werden

Dies bedeutet also im Grunde, dass Variablen, die in einem Delegierten deklariert sind, den Umfang der Funktion erklärt. Nicht genau das, was ich erwartet hätte. Ich habe nicht einmal versucht, die Funktion aufzurufen. Zumindest Common Lisp hat eine Funktion, in der Sie sagen, dass eine Variable einen dynamischen Namen haben sollte, wenn Sie wirklich möchten, dass sie lokal ist. Dies ist besonders wichtig, wenn Makros erstellt werden, die nicht auslaufen, aber so etwas wäre auch hier hilfreich.

Ich frage mich also, was andere Leute tun, um dieses Problem zu umgehen.

Um zu verdeutlichen, suche ich nach einer Lösung, in der die Variablen, die ich im Deleget erkläre nach der Delegierte. Und ich möchte immer noch in der Lage sein, Variablen zu erfassen, die vor dem Delegierten deklariert wurden.

War es hilfreich?

Lösung

Es muss so sein, dass anonyme Methoden (und Lambdas) lokale Variablen und Parameter verwenden, die in der enthaltenden Methode eingegangen sind.

Die Problemumgehungen sollen entweder unterschiedliche Namen für die Variable verwenden oder eine gewöhnliche Methode erstellen.

Andere Tipps

Die von einer anonymen Funktion erstellte "Verschluss" unterscheidet sich etwas von der in anderen dynamischen Sprachen erzeugten (ich werde JavaScript als Beispiel verwenden).

function thing() {
    var o1 = {n:1}
    var o2 = {dummy:"Hello"}
    return function() { return o1.n++; }
}

var fn = thing();
alert(fn());
alert(fn());

Dieser kleine Stück JavaScript zeigt 1 an, dann 2. Die anonyme Funktion kann auf die O1 -Variable zugreifen, da sie in ihrer Bereichskette vorhanden ist. Die anonyme Funktion hat jedoch einen völlig unabhängigen Bereich, in dem sie eine andere O1 -Variable erzeugen und dadurch alle anderen weiter unten in der Umfangskette verbergen kann. Beachten Sie auch, dass alle Variablen in der gesamten Kette verbleiben, daher O2 weiterhin eine Objektreferenz vorliegt, solange die FN Varialbe die Funktionsreferenz enthält.

Vergleichen Sie nun mit C# anonymen Funktionen:-

class C1 { public int n {get; set;} }
class C2 { public string dummy { get; set; } }

Func<int> thing() {
   var o1 = new C1() {n=1};
   var o2 = new C2() {dummy="Hello"};
   return delegate { return o1.n++; };
}
...
Func<int> fn = thing();
Console.WriteLine(fn());
Console.WriteLine(fn());

In diesem Fall erstellt die anonyme Funktion keinen wirklich unabhängigen Bereich mehr als eine variable Deklaration in einem anderen Infunktion {} Code-Block wäre (verwendet in a foreach, if, etc.)

Daher gelten dieselben Regeln, Code außerhalb des Blocks kann keine im Block deklarierten Variablen zugreifen, aber Sie können auch keine Kennung wiederverwenden.

Es wird ein Verschluss erstellt, wenn die anonyme Funktion außerhalb der Funktion übergeben wird, in der sie erstellt wurde. Die Variation vom Beispiel für JavaScript ist, dass nur die Variablen, die tatsächlich von der anonymen Funktion verwendet werden, verbleiben, daher in diesem Fall das von O2 gehaltene Objekt wird für GC verfügbar sein, sobald die Sache abgeschlossen ist,

Sie erhalten auch CS0136 aus dem Code wie folgt:

  int i = 0;
  if (i == 0) {
    int i = 1;
  }

Der Umfang der 2. Deklaration von "I" ist eindeutig, Sprachen wie C ++ haben kein Rindfleisch dabei. Aber die C# -sprachdesigner beschlossen, es zu verbieten. Glaubst du angesichts des oben genannten Snippets immer noch, dass das eine schlechte Idee war? Werfen Sie eine Reihe zusätzlicher Code ein und Sie können diesen Code für eine Weile auf den Fehler starren und den Fehler nicht sehen.

Die Problemumgehung ist trivial und schmerzlos, finden Sie einfach einen anderen variablen Namen.

Dies liegt daran, dass der Delegierte Variablen außerhalb des Delegierten verweisen kann:

int i = 1;
VoidFunction t = delegate { Console.WriteLine(i); };

Wenn ich mich richtig erinnere, erstellt der Compiler ein Klassenmitglied der in der anonymen Methode verwiesenen externen Variablen, um diese Arbeit zu machen.

Hier ist eine Problemumgehung:

class Program
    {
        void Main()
        {
            VoidFunction t = RealFunction;
            int i = 1;
        }
        delegate void VoidFunction();
        void RealFunction() { int i = 0; }
    } 

Tatsächlich scheint der Fehler nichts mit anonymen Delegierten oder Lamda -Ausdrücken zu tun zu haben. Wenn Sie versuchen, das folgende Programm zu kompilieren ...

using System;

class Program
{
    static void Main()
    {
        // Action t = delegate
        {
            int i = 0;
        };

        int i = 1;
    }
}

... Sie erhalten genau den gleichen Fehler, egal ob Sie in der Zeile kommentieren oder nicht. Das Fehlerhilfe zeigt einen sehr ähnlichen Fall. Ich denke, es ist vernünftig, beide Fälle mit der Begründung zu vermeiden, dass Programmierer die beiden Variablen verwirren könnten.

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top