Novidades no C#

A possibilidade de marcar métodos locais como estáticos melhora a expressividade e pode melhorar a performance

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.

Em Resumo
  • O fato

    Métodos grandes são, geralmente, mais difíceis de entender e manter. Por isso, é comum aplicar refatoração extraindo métodos. Muitas vezes, entretanto, o código extraído não tem aplicabilidade fora do trecho que o originou e acaba violando encapsulamento. Desde o C# 7, para evitar esse "vazamento" de lógica, temos a possibilidade de criar métodos locais, inclusive com captura de estado - porém, quando há captura, a mais pressão sobre o GC
  • A novidade

    A partir do C# 8, podemos declarar métodos locais como estáticos. Isso melhora a expressividade do código e garante, durante a compilação, que capturas de estado não ocorram, impedindo pressão sobre o GC.

Mais posts da série Novidades no C#

1 comentário
  1. Luiz ADOLPHS

    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 🙂

Deixe uma resposta

O seu endereço de e-mail não será publicado. Campos obrigatórios são marcados com *