Usando expressões lambda para manipuladores de eventos

114

Atualmente, tenho uma página que é declarada da seguinte forma:

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

Mudei recentemente para .NET 3.5 do 1.1, então estou acostumado a escrever manipuladores de eventos fora do Page_Load. Minha pergunta é; Há alguma desvantagem de desempenho ou armadilha que devo observar ao usar o método lambda para isso? Eu prefiro, pois certamente é mais conciso, mas não quero sacrificar o desempenho para usá-lo. Obrigado.

Christopher Garcia
fonte

Respostas:

117

Não há implicações de desempenho, pois o compilador irá traduzir sua expressão lambda em um delegado equivalente. As expressões lambda nada mais são do que um recurso de linguagem que o compilador traduz no mesmo código com o qual você está acostumado a trabalhar.

O compilador converterá o código que você tem em algo assim:

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
fonte
Entendo. Portanto, também não há nenhuma desvantagem em ter esses manipuladores dentro do Page_Load em comparação a tê-los fora dele?
Christopher Garcia,
1
A convenção prevalecente é anexar manipuladores de eventos no OnInitmétodo, mas como o Clickevento de um botão será gerado após o carregamento da página, este exemplo é adequado.
Andrew Hare
8
É importante observar que, sem manter uma referência ao delegado, você não pode cancelar a inscrição no evento.
snarf
3
"exatamente o mesmo código" é um pouco enganador; pelo menos ao fazer referência a variáveis ​​locais do método envolvente, as expressões lambda não são traduzidas em métodos e em algo como um objeto de fechamento que armazena os valores atuais das variáveis ​​locais.
OR Mapper
66

Em termos de desempenho, é o mesmo que um método nomeado. O grande problema é quando você faz o seguinte:

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

Ele provavelmente tentará remover um lambda diferente, deixando o original lá. Portanto, a lição é que está tudo bem, a menos que você também queira remover o manipulador.

Gabe
fonte
3
" Provavelmente tentará ..."? Será que alguma vez removerá o manipulador correto em tal situação?
OR Mapper
1
@ORMapper: se o lambda captura uma variável, ele não pode remover o manipulador correto. Em outras circunstâncias, depende do compilador.
Gabe
Realmente? Interessante - então, se eu registrar duas funções anônimas que parecem iguais (wlog tem um corpo vazio) e, em seguida, cancelar o registro (usando -=) outra função anônima que também tem um corpo vazio, é essencialmente indefinido qual dos dois manipuladores de eventos irá ser removido, ou se algum deles será removido?
OR Mapper
4
@ORMapper: Sim. O compilador pode (mas não precisa) fazer delegados iguais se eles tiverem semântica idêntica (o código não precisa ser o mesmo, mas eles devem fazer a mesma coisa) e capturar as mesmas instâncias de variáveis ​​(não apenas mesmas variáveis, mas as mesmas instâncias dessas variáveis). Consulte a seção 7.10.8 (Operadores de igualdade delegados) da especificação C # para todos os detalhes.
Gabe
12
Se você realmente deseja usar o lambda, mas precisa remover o evento, você sempre pode manter o objeto em uma variável / campo local e removê-lo, por exemplovar 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
fonte
1
Informações muito úteis, embora fora do tópico (a questão é sobre desempenho).
Stéphane Gourichon
4
Não exatamente fora do assunto, já que o uso de memória pode levar ao rebaixamento do desempenho.
Vladius,
3
Remover-se em um manipulador também pode ser útil:c# EventHandler handler = null; handler = (s, e) => { MessageBox.Show("Woho"); button.Click -= handler;}
Vladius
2

Nenhuma implicação de desempenho que eu conheça ou que já tenha encontrado, até onde eu sei, é apenas "açúcar sintático" e compila para a mesma coisa que usar sintaxe delegada, etc.

Heisenberg
fonte