Використання лямбда-виразів для обробників подій


114

На даний момент у мене є сторінка, яка оголошена так:

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

Нещодавно я перейшов до .NET 3.5 з 1.1, тому звик писати обробники подій поза сторінки Page_Load. Моє запитання; чи є якісь недоліки в роботі або підводні камені, на які я повинен бути уважним, використовуючи для цього метод лямбда? Я вважаю за краще, оскільки це, безумовно, більш стисло, але я не хочу жертвувати продуктивністю, щоб використовувати його. Дякую.

Відповіді:


117

Немає ніяких наслідків для продуктивності, оскільки компілятор переведе ваш лямбда-вираз у еквівалентний делегат. Лямбда-вирази - це не що інше, як мовна функція, яку компілятор перекладає в той самий код, з яким ви звикли працювати.

Компілятор перетворить код, який у вас є, на щось подібне:

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

Я бачу. Тож чи немає також недоліків у наявності цих обробників всередині Page_Load порівняно з їх наявністю поза ним?
Крістофер Гарсія

1
Переважаючим умовою є приєднання обробників подій у OnInitметоді, але оскільки Clickподія кнопки буде піднято після завантаження сторінки, цей приклад добре.
Ендрю Заєць

8
Важливо зазначити, що не зберігаючи посилання на делегата, ви не можете скасувати підписку на подію.
snarf

3
"точно той же код" трохи вводить в оману; принаймні, при посиланні на локальні змінні з методу вкладення, лямбда-вирази не перекладаються на методи і щось на зразок об'єкта закриття, який зберігає поточні значення локальних змінних.
АБО Mapper

66

Виконання продуктивності - це те саме, що іменований метод. Велика проблема полягає в тому, що ви робите наступне:

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

Напевно, спробують видалити іншу лямбда, залишивши там оригінальну. Отже, урок полягає в тому, що це добре, якщо ви також не хочете мати можливість зняти обробник.


3
" Мабуть, спробує ..."? Чи коли-небудь видалить правильний обробник у такій ситуації?
АБО Mapper

1
@ORMapper: Якщо лямбда захоплює змінну, вона не може видалити правильний обробник. В інших умовах справа залежить від компілятора.
Гейб

Дійсно? Цікаво - отже, якщо я зареєструю дві анонімні функції, які виглядають однаково (wlog має порожнє тіло), а потім я скасую (використовую -=) ще одну анонімну функцію, яка теж має порожнє тіло, по суті не визначено, хто з двох обробників подій буде чи буде видалено будь-який із них?
АБО Mapper

4
@ORMapper: Так. Компілятору дозволено (але не обов'язково) робити рівних делегатів, якщо вони мають однакову семантику (код не повинен бути однаковим, але вони повинні робити те саме) і фіксувати однакові екземпляри змінної (не тільки ті ж змінні, але однакові екземпляри цих змінних). Дивіться розділ 7.10.8 (Делегувати оператори рівності) специфікації C # для всіх деталей.
Гейб

12
Якщо ви дійсно хочете використовувати лямбда, але вам потрібно видалити подію, ви завжди можете утримувати об'єкт у локальній змінній / полі, а потім видалити це, наприклад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;

1
Дуже корисна інформація, хоча це поза темою (питання стосується продуктивності).
Stéphane Gourichon

4
Не зовсім поза темою, оскільки використання пам'яті може призвести до зниження продуктивності.
Владіус

3
Видалення себе в обробник також може бути корисним:c# EventHandler handler = null; handler = (s, e) => { MessageBox.Show("Woho"); button.Click -= handler;}
Владіус

2

Жодних наслідків для продуктивності, про які я знаю або коли-небудь стикався, наскільки я знаю його просто "синтаксичний цукор" і складається до того ж, що і за допомогою синтаксису делегата тощо.

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.