Vantagens de usar métodos estáticos privados

209

Ao criar uma classe que possui métodos privados internos, geralmente para reduzir a duplicação de código, que não exige o uso de nenhum campo de instância, existem vantagens de desempenho ou memória em declarar o método como estático?

Exemplo:

foreach (XmlElement element in xmlDoc.DocumentElement.SelectNodes("sample"))
{
    string first = GetInnerXml(element, ".//first");
    string second = GetInnerXml(element, ".//second");
    string third = GetInnerXml(element, ".//third");
}

...

private static string GetInnerXml(XmlElement element, string nodeName)
{
    return GetInnerXml(element, nodeName, null);
}

private static string GetInnerXml(XmlElement element, string nodeName, string defaultValue)
{
    XmlNode node = element.SelectSingleNode(nodeName);
    return node == null ? defaultValue : node.InnerXml;
}

Existe alguma vantagem em declarar os métodos GetInnerXml () como estáticos? Nenhuma resposta de opinião, por favor, tenho uma opinião.

NerdFury
fonte
1
possível duplicação de método pode ser feita estática, mas deveria?
Drzaus 6/08/15

Respostas:

221

Na página de regras do FxCop, consulte :

Depois de marcar os métodos como estáticos, o compilador emitirá sites de chamada não virtuais para esses membros. A emissão de sites de chamada não virtuais impedirá uma verificação em tempo de execução de cada chamada, garantindo que o ponteiro do objeto atual seja não nulo. Isso pode resultar em um ganho de desempenho mensurável para código sensível ao desempenho. Em alguns casos, a falha no acesso à instância atual do objeto representa um problema de correção.

Scott Dorman
fonte
37
Eu também acrescentaria que uma cláusula "estática" não prejudica e já fornece alguma "documentação" com 1 palavra. Diz-lhe que este método não está usando qualquer membro de instância, e você começa esta documentação quase de graça
frandevel
20
Eu diria até: "Se um método não precisar de acesso ao estado (isso), torne-o estático" como regra geral.
DanMan
3
No interesse do equilíbrio, vale ressaltar que muitas pessoas geralmente são contra métodos estáticos porque quebram o polimorfismo e significam que o objeto não pode ser removido para teste. por exemplo, consulte googletesting.blogspot.co.uk/2008/12/…
Andy
@ Andy - Bom ponto. Uma maneira de traçar a linha seria verificar se o método estático está acessando algo fora dos parâmetros que você passa. Contanto que seja autônomo dessa maneira, deve ser fácil testar e não há necessidade stub qualquer coisa.
Neil
4
Muitos desenvolvedores não estão familiarizados com "estática privada". Eu o usei na base de código comum da minha equipe e isso causou confusão. Em troca, fornece benefícios muito menores. Poderíamos optar por educar todos da equipe, incluindo todos os futuros desenvolvedores que mantêm o código, sobre o que isso significa. Mas o benefício de mudar um método privado para uma estática privada é tão pequeno (ou seja, remover a dependência dos dados da instância), que não vale a pena o esforço e a confusão. O método já tem escopo privado de qualquer maneira. É uma peculiaridade linguística que não é realmente necessária.
precisa
93

Quando estou escrevendo uma classe, a maioria dos métodos se enquadra em duas categorias:

  • Métodos que usam / alteram o estado da instância atual.
  • Métodos auxiliares que não usam / alteram o estado do objeto atual, mas me ajudam a calcular os valores que preciso em outro lugar.

Os métodos estáticos são úteis, porque, ao olhar para sua assinatura, você sabe que a chamada não usa nem modifica o estado da instância atual.

Veja este exemplo:

Biblioteca de classe pública
{
    livro estático privado findBook (Lista de livros <Livro>, título da sequência)
    {
        // código aqui
    }
}

Se uma instância do estado da biblioteca for estragada, e eu estou tentando descobrir o porquê, posso excluir o findBook como o culpado, apenas a partir de sua assinatura.

Tento me comunicar o máximo possível com a assinatura de um método ou função, e essa é uma excelente maneira de fazer isso.

Neil
fonte
1
Tipo de declaração de método const em C ++, não é?
anhoppe
Sim - essa é outra boa maneira de usar a linguagem para simplificar as coisas, limitando o que pode dar errado.
Neil
Isto não é necessariamente verdade. Vamos supor que a Librarypossua um campo de instância List<Book> _bookspara armazenar seus livros (não como você Libraryprovavelmente projetaria uma classe, mas w / e), e ela passa essa lista para findBook, e esse método estático chama books.Clear()ou books.Reverse()assim por diante. Se você conceder a um método estático acesso a uma referência a algum estado mutável, esse método estático pode muito bem atrapalhar seu estado.
Sara
1
Verdade. E, nesse caso, a assinatura nos mostraria que esse método tinha acesso (e a capacidade de alterar) uma instância da Library.
Neil
Para praticamente qualquer construto de proteção que possamos usar, há alguma maneira de miná-lo. Mas usá-los ainda é sábio e ajuda a nos levar na direção certa, em direção ao "poço do sucesso".
Neil
81

Uma chamada para um método estático gera uma instrução de chamada na linguagem intermediária da Microsoft (MSIL), enquanto uma chamada para um método de instância gera uma instrução callvirt, que também verifica referências a objetos nulos. No entanto, na maioria das vezes a diferença de desempenho entre os dois não é significativa.

src: MSDN - http://msdn.microsoft.com/en-us/library/79b3xss3(v=vs.110).aspx

Marek Takac
fonte
15

Sim, o compilador não precisa passar o thisponteiro implícito para os staticmétodos. Mesmo que você não o use no método da instância, ele ainda está sendo passado.

Kent Boogaart
fonte
Como isso se relaciona a uma vantagem de desempenho ou memória em tempo de execução?
Scott Dorman
11
Passar um parâmetro extra significa que a CPU precisa fazer um trabalho extra para colocar esse parâmetro em um registro e empurrá-lo para a pilha se o método da instância chamar outro método.
Kent Boogaart 25/09/08
5

Será um pouco mais rápido, pois esse parâmetro não foi passado (embora o custo de desempenho da chamada do método seja provavelmente consideravelmente maior do que essa economia).

Eu diria que a melhor razão pela qual posso pensar em métodos estáticos privados é que isso significa que você não pode alterar acidentalmente o objeto (pois não há esse ponteiro).

Gnu grátis
fonte
4

Isso obriga a lembrar também de declarar quaisquer membros com escopo de classe que a função use como estática também, o que deve economizar a memória de criar esses itens para cada instância.

Joel Coehoorn
fonte
Só porque é uma variável com escopo de classe, não significa que deve ser estática.
Scott Dorman
3
Não, mas se for usado por um método estático, DEVE ser estático. Se o método não fosse estático, talvez você não tivesse tornado o membro da classe estático e isso resultaria em mais memória usada para cada instância da classe.
Joel Coehoorn
2

Eu prefiro que todos os métodos privados sejam estáticos, a menos que realmente não possam ser. Eu preferiria muito o seguinte:

public class MyClass
{
    private readonly MyDependency _dependency;

    public MyClass(MyDependency dependency)
    {
        _dependency = dependency;
    }

    public int CalculateHardStuff()
    {
        var intermediate = StepOne(_dependency);
        return StepTwo(intermediate);
    }

    private static int StepOne(MyDependency dependency)
    {
        return dependency.GetFirst3Primes().Sum();
    }

    private static int StepTwo(int intermediate)
    {
        return (intermediate + 5)/4;
    }
}

public class MyDependency
{
    public IEnumerable<int> GetFirst3Primes()
    {
        yield return 2;
        yield return 3;
        yield return 5;
    }
}

sobre todos os métodos que acessam o campo da instância. Por que é isso? Como esse processo de cálculo se torna mais complexo e a classe termina com 15 métodos auxiliares particulares, eu REALMENTE quero poder puxá-los para uma nova classe que encapsule um subconjunto de etapas de uma maneira semanticamente significativa.

Quando MyClassobtém mais dependências porque precisamos de log e também notificamos um serviço da web (desculpe os exemplos de clichê), é realmente útil ver facilmente quais métodos têm quais dependências.

Ferramentas como o R # permitem extrair uma classe de um conjunto de métodos estáticos privados com apenas algumas teclas. Tente fazer isso quando todos os métodos auxiliares privados estiverem fortemente acoplados ao campo da instância e você verá que pode ser uma dor de cabeça.

sara
fonte
-3

Como já foi afirmado, existem muitas vantagens nos métodos estáticos. Contudo; lembre-se de que eles permanecerão na pilha pela vida útil do aplicativo. Recentemente, passei um dia rastreando um vazamento de memória em um serviço do Windows ... o vazamento foi causado por métodos estáticos privados dentro de uma classe que implementou IDisposable e foi consistentemente chamado a partir de uma instrução using. Cada vez que essa classe foi criada, a memória era reservada no heap para os métodos estáticos da classe; infelizmente, quando a classe foi descartada, a memória dos métodos estáticos não foi liberada. Isso fez com que a pegada de memória desse serviço consumisse a memória disponível do servidor dentro de alguns dias, com resultados previsíveis.

James Haumann
fonte
4
Isso não faz sentido. A pilha nunca armazena memória para o código para nenhum método, estático ou não. A pilha é para instâncias de objetos. Haverá dados na pilha para qualquer chamada de qualquer método (para armazenar a memória para os parâmetros, valor de retorno, locais não içados, etc.), mas tudo isso desaparece quando o método termina de executar.
Servy