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 🙂