A recomendação padrão é para que escrevamos métodos pequenos. Quanto menor for um método, geralmente, menos tempo é necessário para entender seu propósito e mais barata é a manutenção. De qualquer forma, as vezes, alguns métodos são naturalmente grandes e não há muito que possamos fazer.
Uma forma comum de acabar com métodos grandes é tentar extrair deles trechos de lógica que “funcionem” como métodos, menores, independentes. Aliás, essa, talvez, seja a técnica mais comum de refatoração. Quando os métodos extraídos tem potencial para serem “públicos” – ou seja, são úteis em “outros lugares” além do código onde foi extraído – ganha-se com reaproveitamento e testabilidade. Infelizmente, esse nem sempre é o caso.
Muitas vezes, métodos extraídos tem utilidade restrita apenas ao código que os originaram. Por isso, ficam anotados como privados na mesma classe onde está o método original. Nesses casos, entretanto, sendo preciosistas, entendemos que há uma violação do encapsulamento. Afinal, esse trecho de código fica visível para os demais métodos da classe.
A partir do C# 7, é possível “extrair métodos” deixando-os locais. Ou seja, visíveis apenas para o contexto do código de onde foram extraídos. Os métodos locais podem, inclusive, utilizar variáveis do contexto do método “pai”, através de captura, gerando pressão sobre o GC.
A partir do C# 8, é possível declarar métodos locais como estáticos, garantido que não ocorram capturas de estado, e consequentemente, pressionando menos o GC.
public static bool ValidarCPF(string sourceCPF) { static bool VerificaTodosValoresSaoIguais(ref Span<int> input) { for (var i = 1; i < 11; i++) { if (input[i] != input[0]) { return false; } } return true; } if (string.IsNullOrWhiteSpace(sourceCPF)) return false; Span<int> cpfArray = stackalloc int[11]; var count = 0; foreach (var c in sourceCPF) { if (char.IsDigit(c)) { if (count > 10) { return false; } cpfArray[count] = c - '0'; count++; } } if (count != 11) return false; if (VerificaTodosValoresSaoIguais(ref cpfArray)) return false; var totalDigitoI = 0; var totalDigitoII = 0; int modI; int modII; for (var posicao = 0; posicao < cpfArray.Length - 2; posicao++) { totalDigitoI += cpfArray[posicao] * (10 - posicao); totalDigitoII += cpfArray[posicao] * (11 - posicao); } modI = totalDigitoI % 11; if (modI < 2) { modI = 0; } else { modI = 11 - modI; } if (cpfArray[9] != modI) { return false; } totalDigitoII += modI * 2; modII = totalDigitoII % 11; if (modII < 2) { modII = 0; } else { modII = 11 - modII; } return cpfArray[10] == modII; }
A utilização de métodos locais divide opiniões e sua aplicabilidade para o bom design do código merece mais discussões.
De qualquer forma, quando escolhemos usar métodos locais, ter a opção de indicá-los como estáticos melhora a expressividade código, permitindo que o programador indique que não há a intenção de capturar o estado do contexto de execução, podendo contar com a ajuda do compilador para garantir isso.
Métodos locais tanto estáticos ou não geram métodos privados ao serem compilados para o intermediate language né? Eu gostei de métodos locais por que:
1 – Acho que seria mais performático frente a alternativa antiga que era o Action ou Func
2 – Agora com a versão estática deve ficar ainda mais… não acho que exista equivalência na versão < 7
3 – O que o artigo diz sobre encapsulamento 🙂