Os atributos são uma parte essencial dos recursos de processamento de metadados no .NET. Eles são usados por compiladores, analisadores estáticos e bibliotecas de tempo de execução para diversas finalidades. Enquanto funções/métodos normais podem ter atributos, antes desta proposta, lambdas e funções anônimas não podiam.
Embora, em teoria, qualquer atributo aplicável a funções/métodos normais possa ser utilizado em um lambda, há novos atributos sendo considerados especificamente para eles. Esses novos atributos controlam o que pode ser capturado pelo lambda.
- CaptureNone: Nenhuma variável pode ser capturada. O lambda será compilado como uma função estática.
- CaptureThis: Somente o ponteiro "this" será capturado. O lambda será compilado como um método.
- CaptureAny: Qualquer variável local pode ser capturada. O lambda será compilado como parte de um objeto de fechamento anônimo.
Ao trabalhar com código sensível ao desempenho, o CaptureAny deve ser evitado porque um novo objeto de fechamento correspondente e um delegate precisam ser criados para cada instância. CaptureThis não é tão ruim, mas um novo delegate ainda deve ser alocado. Esse delegate pode resultar em uso ineficiente de memória se mantiver o objeto externo ativo por mais tempo do que o necessário. Finalmente, o CaptureNone precisaria apenas criar uma instância de um delegate que pudesse ser reutilizada durante a vida útil do aplicativo.
Quando aplicado a um lambda, os atributos seriam usados pelo compilador ou por um analisador para garantir que o lambda do CaptureNone não seja acidentalmente alterado para um tipo menos eficiente no futuro. Essencialmente, os atributos atuariam como uma forma de documentação.
Este conceito não é novo. Por exemplo, em lambdas de C++, é preciso listar explicitamente todas as variáveis que o lambda pode capturar. A diferença aqui é que os atributos seriam opcionais em C# (a menos que seja aplicado de outra forma por um analisador).
Sob esta proposta, os atributos também podem ser adicionados aos parâmetros de um lambda. Para evitar confusão, os parâmetros devem estar entre parênteses quando usar atributos. Se o atributo também estiver dentro do parênteses, então aplica-se ao parâmetro. Atributos fora dos parênteses se aplicam ao lambda como um todo.
Para mais informações, consulte a proposta de Atributos do Lambda no GitHub.