25 Stimmen

Lokale Variablen mit Delegaten

Diese ist eindeutig nicht scheint nicht die beste Praxis zu sein. Kann mir jemand erklären, warum das keine bewährte Praxis ist oder wie das funktioniert? Für Bücher oder Artikel, die eine Erklärung liefern, wären wir dankbar.

//The constructor
public Page_Index() {

    //create a local value
    string currentValue = "This is the FIRST value";

    //use the local variable in a delegate that fires later
    this.Load += delegate(object sender, EventArgs e) {
        Response.Write(currentValue);
    };

    //change it again
    currentValue = "This is the MODIFIED value";

}

Der Wert, der ausgegeben wird, ist der zweite Wert "Geändert" . Welcher Teil der Compiler-Magie sorgt dafür, dass dies funktioniert? Ist es so einfach, wie den Wert auf dem Heap zu speichern und ihn später wieder abzurufen?

[Bearbeiten]: In Anbetracht einiger Kommentare sollte der ursprüngliche Satz etwas geändert werden...

0 Stimmen

An dieser Praxis ist nichts auszusetzen. Sie ist nur fortgeschrittener, als es Anfänger verstehen würden.

0 Stimmen

Es kann sogar für ein sehr sauberes/elegantes Design sorgen - aber man muss sich über die Auswirkungen im Klaren sein.

0 Stimmen

Das ist wirklich sehr interessant. Ich würde nicht denken, dass das Herumspielen mit lokalen Variablen innerhalb des Bereichs, der dem Delegaten zugewiesen wurde, eine gute Praxis wäre, aber man lernt immer wieder etwas Neues.

32voto

Marc Gravell Punkte 970173

CurrentValue ist nicht länger eine lokale Variable: Es ist eine gefangen variabel. Dies bedeutet in etwa:

class Foo {
  public string currentValue; // yes, it is a field

  public void SomeMethod(object sender, EventArgs e) {
    Response.Write(currentValue);
  }
}
...
public Page_Index() {
  Foo foo = new Foo();
  foo.currentValue = "This is the FIRST value";
  this.Load += foo.SomeMethod;

  foo.currentValue = "This is the MODIFIED value";
}

Jon Skeet hat einen wirklich guten Bericht darüber in C# in der Tiefe und eine separate (nicht so ausführliche) Diskussion aquí .

Beachten Sie, dass sich die Variable currentValue jetzt auf dem Heap und nicht auf dem Stack befindet - dies hat viele Auswirkungen, nicht zuletzt, dass sie jetzt von verschiedenen Aufrufern verwendet werden kann.

Dies ist ein Unterschied zu Java: In Java wird die Wert einer Variablen erfasst wird. In C# wird die Variable selbst erfasst wird.

0 Stimmen

Neben dem Artikel in C# in Depth (danke für die Werbung!) habe ich auch einen Artikel geschrieben, in dem ich C#- und Java-Closures vergleiche und erkläre, warum sie gut sind: csharpindepth.com/Artikel/Kapitel5/Verschlüsse.aspx

0 Stimmen

Ah - während Sie diesen Kommentar schrieben, habe ich den obigen Text bearbeitet, um ihn mit aufzunehmen. Der doppelte Wert ;-p

0 Stimmen

@Mark: Um Ihre großartige Antwort noch ein wenig zu verbessern, könnten Sie die Variable " Wert " von " Wert der Variablen " in Ihrem letzten Satz? Da die Variable "currentValue" heißt, kann es den Leser (wie mich) verwirren, wenn er zuerst denkt, dass das kursive " Wert " bezieht sich auf die Name der Variablen (" welche Variable? Die Variable mit dem Namen Wert ")

2voto

Marc Gravell Punkte 970173

Ich nehme an, die Frage, die ich stelle, lautet: Wie funktioniert das mit einer lokalen Variablen? [MG edit: "Ack - ignore this..." wurde nachträglich hinzugefügt]

Das ist der Punkt; es ist wirklich n'est pas eine lokale Variable nicht mehr - zumindest nicht in dem Sinne, wie wir sie uns normalerweise vorstellen (auf dem Stack usw.). Sie sieht wie eine aus, ist es aber nicht.

Und zur Info, re "nicht gute Praxis" - anonyme Methoden und erfasste Variablen sind tatsächlich ein unglaublich mächtiges Werkzeug, insbesondere bei der Arbeit mit Ereignissen. Es steht Ihnen frei, sie zu verwenden, aber wenn Sie diesen Weg gehen, würde ich empfehlen, Jons Buch zu lesen, um sicherzustellen, dass Sie verstehen, was tatsächlich passiert.

0voto

leppie Punkte 111830

Sie müssen den Wert der Variablen innerhalb der Schließung/des Delegaten erfassen, da er sonst geändert werden kann, wie Sie gesehen haben.

Weisen Sie currentValue einer Variablen zu, die lokal (innerhalb) des Delegaten liegt.

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X