Olay işleyicileri için lambda ifadelerini kullanma


114

Şu anda aşağıdaki gibi ilan edilen bir sayfam var:

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

Yakın zamanda 1.1'den .NET 3.5'e geçtim, bu yüzden Page_Load'un dışında olay işleyicileri yazmaya alıştım. Sorum şu; Bunun için lambda yöntemini kullanırken dikkat etmem gereken performans sakıncaları veya tuzakları var mı? Kesinlikle daha kısa olduğu için tercih ediyorum, ancak kullanmak için performanstan ödün vermek istemiyorum. Teşekkürler.

Yanıtlar:


117

Derleyici lambda ifadenizi eşdeğer bir temsilciye çevireceğinden, hiçbir performans etkisi yoktur. Lambda ifadeleri, derleyicinin çalışmaya alışkın olduğunuz koda çevirdiği bir dil özelliğinden başka bir şey değildir.

Derleyici, sahip olduğunuz kodu aşağıdaki gibi bir şeye dönüştürecektir:

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
        });
    }
}

Anlıyorum. Öyleyse, bu işleyicilerin Page_Load içinde olmasının ve bunların dışında olmalarının bir sakıncası yok mu?
Christopher Garcia

1
Geçerli kural, OnInityönteme olay işleyicileri eklemektir, ancak Clicksayfa yüklendikten sonra bir düğmenin olayı ortaya çıkacağı için bu örnek uygundur.
Andrew Hare

8
Temsilciye bir referans tutmadan, etkinlik aboneliğinden çıkamayacağınızı unutmamak gerekir.
snarf

3
"tam olarak aynı kod" biraz yanıltıcıdır; en azından çevreleyen yöntemden yerel değişkenlere referans verirken, lambda ifadeleri yöntemlere ve yerel değişkenlerin mevcut değerlerini saklayan bir kapanış nesnesi gibi bir şeye dönüştürülmez .
VEYA Mapper

66

Performans açısından adlandırılmış bir yöntemle aynıdır. En büyük sorun, aşağıdakileri yaptığınızda:

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

Muhtemelen farklı bir lambdayı çıkarmaya çalışacak ve orjinalini orada bırakacaktır. Dolayısıyla, işleyiciyi de kaldırmak istemediğiniz sürece ders şu ki, sorun değil.


3
" Muhtemelen deneyecek ..."? O Will Hiç böyle bir durum doğru işleyicisi kaldırmak?
VEYA Mapper

1
@ORMapper: Lambda bir değişkeni yakalarsa, doğru işleyiciyi kaldıramaz. Diğer durumlarda, derleyiciye kalmıştır.
Gabe

Gerçekten mi? İlginç - yani, aynı görünen iki anonim işlevi kaydedersem (wlog boş bir gövdeye sahiptir) ve sonra -=da boş bir gövdeye sahip başka bir anonim işlevin kaydını silersem (kullanarak ), iki olay işleyicisinden hangisinin olacağı aslında tanımsızdır. kaldırılacak mı yoksa bunlardan herhangi biri kaldırılacak mı?
VEYA Mapper

4
@ORMapper: Evet. Derleyicinin aynı semantiğe sahip olmaları halinde (kodun aynı olması gerekmez, ancak aynı şeyi yapmaları gerekir) eşit temsilciler oluşturmasına ve aynı değişken örneklerini (yalnızca aynı değişkenler, ancak bu değişkenlerin aynı örnekleri). Tüm ayrıntılar için C # spesifikasyonunun 7.10.8 (Temsilci eşitlik operatörleri) bölümüne bakın.
Gabe

12
Lambda'yı gerçekten kullanmak istiyor ancak olayı kaldırmanız gerekiyorsa, nesneyi her zaman yerel bir değişkende / alanda tutabilir ve sonra onu kaldırabilirsiniz, örneğinvar 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;

1
Konu dışı olmasına rağmen çok faydalı bilgiler (soru performansla ilgili).
Stéphane Gourichon

4
Bellek kullanımı performansın düşmesine neden olabileceğinden tam olarak konu dışı değildir.
Vladius

3
Kendini bir işleyicide kaldırmak da yardımcı olabilir:c# EventHandler handler = null; handler = (s, e) => { MessageBox.Show("Woho"); button.Click -= handler;}
Vladius

2

Bildiğim kadarıyla, sadece "sözdizimsel şekeri" olduğunu bildiğim ve temsilci sözdizimini kullanarak aynı şeyi derlediğim sürece, farkında olduğum veya şimdiye kadar karşılaştığım hiçbir performans etkisi yok.

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.