Verwenden von Lambda-Ausdrücken für Ereignishandler

114

Ich habe derzeit eine Seite, die wie folgt deklariert ist:

public partial class MyPage : System.Web.UI.Page
{
    protected void Page_Load(object sender, EventArgs e)
    {
        //snip
        MyButton.Click += (o, i) =>
        {
            //snip
        }
    }
}

Ich bin erst kürzlich von 1.1 auf .NET 3.5 umgestiegen, daher bin ich es gewohnt, Ereignishandler außerhalb von Page Load zu schreiben. Meine Frage ist; Gibt es Leistungsnachteile oder Fallstricke, auf die ich bei der Verwendung der Lambda-Methode achten sollte? Ich bevorzuge es, da es sicherlich prägnanter ist, aber ich möchte die Leistung nicht opfern, um es zu verwenden. Vielen Dank.

Christopher Garcia
quelle

Antworten:

117

Es gibt keine Auswirkungen auf die Leistung, da der Compiler Ihren Lambda-Ausdruck in einen äquivalenten Delegaten übersetzt. Lambda-Ausdrücke sind nichts anderes als eine Sprachfunktion, die der Compiler in genau denselben Code übersetzt, mit dem Sie gewohnt sind.

Der Compiler konvertiert den Code, den Sie haben, in etwa Folgendes:

public partial class MyPage : System.Web.UI.Page
{
    protected void Page_Load(object sender, EventArgs e)
    {
        //snip
        MyButton.Click += new EventHandler(delegate (Object o, EventArgs a) 
        {
            //snip
        });
    }
}
Andrew Hare
quelle
Aha. Gibt es also auch keinen Nachteil, wenn diese Handler innerhalb von Page Load vorhanden sind, anstatt sie außerhalb von Page Load zu haben?
Christopher Garcia
1
Die vorherrschende Konvention besteht darin, Ereignishandler an die OnInitMethode anzuhängen. Da jedoch das ClickEreignis einer Schaltfläche nach dem Laden der Seite ausgelöst wird, ist dieses Beispiel in Ordnung.
Andrew Hare
8
Es ist wichtig zu beachten, dass Sie das Ereignis nicht abbestellen können, ohne einen Verweis auf den Delegaten beizubehalten.
Snarf
3
"genau der gleiche Code" ist etwas irreführend; Zumindest beim Verweisen auf lokale Variablen aus der einschließenden Methode werden die Lambda-Ausdrücke nicht in Methoden und so etwas wie ein Abschlussobjekt übersetzt, in dem die aktuellen Werte der lokalen Variablen gespeichert sind.
ODER Mapper
66

In Bezug auf die Leistung entspricht dies einer benannten Methode. Das große Problem ist, wenn Sie Folgendes tun:

MyButton.Click -= (o, i) => 
{ 
    //snip 
} 

Es wird wahrscheinlich versuchen, ein anderes Lambda zu entfernen, wobei das ursprüngliche dort verbleibt. Die Lektion lautet also, dass es in Ordnung ist, wenn Sie nicht auch den Handler entfernen möchten.

Gabe
quelle
3
"Es wird wahrscheinlich versuchen ..."? Wird es in einer solchen Situation jemals den richtigen Handler entfernen?
ODER Mapper
1
@ORMapper: Wenn das Lambda eine Variable erfasst, kann es den richtigen Handler nicht entfernen. Unter anderen Umständen liegt es am Compiler.
Gabe
"Ja wirklich?" Interessant - wenn ich also zwei anonyme Funktionen registriere, die gleich aussehen (wlog hat einen leeren Körper) und dann die Registrierung einer -=anderen anonymen Funktion aufheben (verwenden ), die ebenfalls einen leeren Körper hat, ist im Wesentlichen undefiniert, welcher der beiden Ereignishandler dies tut entfernt werden, oder ob einer von ihnen überhaupt entfernt wird?
ODER Mapper
4
@ORMapper: Ja. Der Compiler darf (muss aber nicht) gleiche Delegaten erstellen, wenn sie identische Semantik haben (der Code muss nicht gleich sein, aber sie müssen dasselbe tun) und dieselben variablen Instanzen erfassen (nicht nur die gleiche Variablen, aber dieselben Instanzen dieser Variablen). Weitere Informationen finden Sie in Abschnitt 7.10.8 (Gleichheitsoperatoren delegieren) der C # -Spezifikation.
Gabe
12
Wenn Sie das Lambda wirklich verwenden möchten, aber das Ereignis entfernen müssen, können Sie das Objekt jederzeit in einer lokalen Variablen / einem lokalen Feld festhalten und dann entfernen, z. B.var event = (o, e) => doSomething(); handler += event; doSomethingElse(); handler -= event;
Wai Ha Lee
44
EventHandler handler = (s, e) => MessageBox.Show("Woho");

button.Click += handler;
button.Click -= handler;
Usama Wahab Khan
quelle
1
Sehr nützliche Informationen, obwohl sie nicht zum Thema gehören (die Frage bezieht sich auf die Leistung).
Stéphane Gourichon
4
Nicht gerade vom Thema abweichend, da die Speichernutzung zu einer Leistungsminderung führen kann.
Vladius
3
Das Entfernen in einem Handler selbst kann ebenfalls hilfreich sein:c# EventHandler handler = null; handler = (s, e) => { MessageBox.Show("Woho"); button.Click -= handler;}
Vladius
2

Keine Auswirkungen auf die Leistung, die mir bekannt sind oder denen ich jemals begegnet bin, soweit ich weiß, dass es sich nur um "syntaktischen Zucker" handelt und der sich auf das Gleiche wie die Verwendung der Delegatensyntax usw. reduziert.

Heisenberg
quelle