Esta é uma extensão da pergunta de Acesso ao Fechamento Modificado . Só quero verificar se o seguinte é realmente seguro o suficiente para uso em produção.
List<string> lists = new List<string>();
//Code to retrieve lists from DB
foreach (string list in lists)
{
Button btn = new Button();
btn.Click += new EventHandler(delegate { MessageBox.Show(list); });
}
Eu só repasso os itens acima uma vez por inicialização. Por enquanto, parece funcionar bem. Como Jon mencionou sobre o resultado contra-intuitivo em alguns casos. Então, o que eu preciso cuidar aqui? Tudo bem se a lista for analisada mais de uma vez?
Respostas:
Antes do C # 5, você precisa declarar novamente uma variável dentro do foreach - caso contrário, ela será compartilhada e todos os seus manipuladores usarão a última string:
De forma significativa, observe que, a partir do C # 5, isso mudou e, especificamente no caso de
foreach
, você não precisa mais fazer isso: o código na questão funcionaria conforme o esperado.Para mostrar que isso não está funcionando sem essa mudança, considere o seguinte:
Execute o procedimento acima antes de C # 5 e, embora cada botão mostre um nome diferente, clicar nos botões mostra "Wilma" quatro vezes.
Isso ocorre porque a especificação de idioma (ECMA 334 v4, 15.8.4) (antes de C # 5) define:
Observe que a variável
v
(que é sualist
) é declarada fora do loop. Portanto, pelas regras das variáveis capturadas, todas as iterações da lista compartilharão o portador da variável capturada.Do C # 5 em diante, isso mudou: a variável de iteração (
v
) tem o escopo dentro do loop. Não tenho uma referência de especificação, mas basicamente se torna:Cancelar a inscrição novamente; se você deseja cancelar a inscrição de um manipulador anônimo, o truque é capturar o próprio manipulador:
Da mesma forma, se você quiser um manipulador de eventos apenas uma vez (como Carregar etc):
Isso agora está cancelando automaticamente ;-p
fonte
for
não mudou em 5.0