O método pode ser feito estático, mas deveria?


366

O resharper gosta de apontar várias funções por página asp.net que podem ser tornadas estáticas. Isso me ajuda se eu as tornar estáticas? Devo torná-los estáticos e movê-los para uma classe de utilidade?


20
O Resharper não está realmente gritando "baixa coesão, baixa coesão"? é hora de verificar se o método realmente pertence a essa classe.
PK

Respostas:


245

Métodos estáticos versus métodos de instância
10.2.5 Os membros estáticos e de instância da Especificação da linguagem C # explicam a diferença. Geralmente, os métodos estáticos podem fornecer um aprimoramento de desempenho muito pequeno em relação aos métodos de instância, mas apenas em situações um pouco extremas (consulte esta resposta para obter mais detalhes sobre isso).

A regra CA1822 no FxCop ou na Análise de código afirma:

"Depois de [marcar os membros como estáticos], o compilador emitirá sites de chamada não virtuais para esses membros, o que impedirá uma verificação em tempo de execução de cada chamada, garantindo que o ponteiro do objeto atual seja 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. "

Classe de utilitário
Você não deve movê-los para uma classe de utilitário, a menos que faça sentido em seu design. Se o método estático se relacionar a um tipo específico, como um ToRadians(double degrees)método a uma classe que representa ângulos, faz sentido que esse método exista como membro estático desse tipo (observe, este é um exemplo complicado para fins de demonstração).


2
> o compilador emitirá sites de chamadas não virtuais para esses membros. Na verdade, "o compilador pode emitir ...". Lembro-me de algo sobre o compilador C # usando callvirt em vez de chamar para solucionar algum bug em potencial.
Jonathan Allen

24
Eu o recortei e colei diretamente do FxCop 1.36. Se o FxCop estiver errado, é justo o suficiente.
Jeff Yates

5
@ Maxim Não tenho certeza se eu aprecio a declaração "besteira"; maneira bem rude de abordar estranhos. No entanto, o ponto subjacente é válido; Atualizei um pouco as coisas (há 9 anos, então não me lembro da base da minha reivindicação original).
21817 Jeff Yates

10
@Maxim Seu ponto é inválido. Garanto-lhe que não tive uma boa classificação há 9 anos. Aprecio comentários que apontem erros (ou edições que os corrijam), mas não sejam rudes nem ponham expectativas irracionais nos outros. Não chame algo de "besteira"; implica uma intenção de enganar, em vez de ser honesto, ao erro ou à ignorância da bondade. É rude. Eu ofereço meu tempo para ajudar aqui e realmente parece inútil quando é tratado com desrespeito. Não me diga pelo que ficar ofendido - essa é minha escolha, não sua. Aprenda como expressar seu ponto de vista com respeito e integridade. Obrigado.
21817 Jeff Yates

2
@ Maxim Embora os delegados não sejam armazenados ao lado de cada instância, cada instância de uma classe sem estado realmente ocupa alguma memória na pilha, o que é uma sobrecarga inútil. Geralmente, a instanciação de serviços não é o caminho mais quente em um aplicativo, mas se o seu aplicativo acabar construindo muitos desses objetos, aumentará a pressão do GC que poderia ser evitada usando simplesmente métodos estáticos. A afirmação original do OP, de que em situações extremas os métodos estáticos fornecem um benefício de desempenho em relação às instâncias sem estado, foi adequadamente diferenciada e válida.
Asad Saeeduddin

259

Desempenho, poluição de namespace, etc, são todos secundários em minha opinião. Pergunte a si mesmo o que é lógico. O método está operando logicamente em uma instância do tipo ou está relacionado ao próprio tipo? Se for o último, torne-o um método estático. Somente mova-o para uma classe de utilitário se estiver relacionado a um tipo que não está sob seu controle.

Às vezes, há métodos que logicamente atuam em uma instância, mas não acontecem de usar qualquer um do estado da instância ainda . Por exemplo, se você estivesse construindo um sistema de arquivos e tivesse o conceito de diretório, mas ainda não o tivesse implementado, poderia escrever uma propriedade retornando o tipo de objeto do sistema de arquivos e sempre seria apenas "arquivo" - mas está logicamente relacionado à instância e, portanto, deve ser um método de instância. Isso também é importante se você deseja tornar o método virtual - sua implementação específica pode não precisar de estado, mas classes derivadas podem. (Por exemplo, perguntando a uma coleção se é ou não somente leitura - talvez você ainda não tenha implementado uma forma somente leitura dessa coleção, mas é claramente uma propriedade da própria coleção, não do tipo.)


11
Eu acho que um bom linter deve ter uma opção para restringir a mensagem a métodos não virtuais, pois seria muito comum que um método de classe base praticamente não fizesse nada. Métodos de substituição geralmente fazem alguma coisa, mas nem sempre. Às vezes, é útil ter uma classe para algo como um iEnumerable vazio, cujos métodos basicamente ignoram a instância, mas onde a instância é necessária para selecionar o método certo a ser usado.
Supercat

2
"Às vezes, existem métodos que agem logicamente em uma instância, mas ainda não usam nenhum estado da instância. Por exemplo" Eu gostei do seu uso de "por exemplo" nesta instância.
PaulBinder

56

Marcar um método como staticdentro de uma classe torna óbvio que ele não usa nenhum membro da instância, o que pode ser útil saber ao percorrer o código.

Você não precisa necessariamente movê-lo para outra classe, a menos que seja destinado a ser compartilhado por outra classe que esteja intimamente associada, em termos de conceito.


22

Tenho certeza de que isso não está acontecendo no seu caso, mas um "mau cheiro" que eu já vi em algum código que tive que sofrer ao manter usado muitos métodos estáticos.

Infelizmente, eram métodos estáticos que assumiram um estado de aplicativo específico. (com certeza, teremos apenas um usuário por aplicativo! Por que a classe User não controla isso em variáveis ​​estáticas?) Elas eram maneiras glorificadas de acessar variáveis ​​globais. Eles também tinham construtores estáticos (!), Que quase sempre são uma má idéia. (Eu sei que existem algumas exceções razoáveis).

No entanto, métodos estáticos são bastante úteis quando fatoram a lógica de domínio que na verdade não depende do estado de uma instância do objeto. Eles podem tornar seu código muito mais legível.

Apenas certifique-se de colocá-los no lugar certo. Os métodos estáticos estão manipulando intrusivamente o estado interno de outros objetos? Pode-se argumentar que o comportamento deles pertence a uma dessas classes? Se você não está separando as preocupações corretamente, pode ter dores de cabeça mais tarde.


4
Seu problema é com campos / propriedades estáticos, não com métodos estáticos.
Asad Saeeduddin

10

Esta é uma leitura interessante:

http://thecuttingledge.com/?p=57

O ReSharper não está sugerindo que você torne seu método estático. Você deve se perguntar por que esse método está nessa classe, em vez de, digamos, uma das classes que aparece em sua assinatura ...

mas aqui está o que a documentação do novo compartilhador diz: http://confluence.jetbrains.net/display/ReSharper/Member+can+be+made+static


2
Eu acho que esse ponto é subestimado. O que a ferramenta realmente está dizendo é que o método opera apenas com os membros de outras classes. Se for algum tipo de objeto de comando (ou "caso de uso" ou "interator"), quem é responsável por manipular outros objetos, tudo bem. No entanto, se ele manipular apenas uma única outra classe que se pareça muito com o Feature Envy .
187 Greg Greg

9

Apenas para adicionar à resposta de @Jason True , é importante perceber que apenas colocar 'estático' em um método não garante que o método seja 'puro'. Ele será sem estado no que diz respeito à classe em que é declarado, mas pode acessar outros objetos 'estáticos' com estado (configuração do aplicativo etc.); isso nem sempre é uma coisa ruim, mas um dos motivos pelos quais Pessoalmente, tendem a preferir métodos estáticos quando posso: se eles forem puros, você poderá testar e argumentar isoladamente, sem ter que se preocupar com o estado circundante.


6

Você deve fazer o que for mais legível e intuitivo em um determinado cenário.

O argumento de desempenho não é bom, exceto nas situações mais extremas, pois a única coisa que realmente está acontecendo é que um parâmetro extra ( this) está sendo empurrado para a pilha por métodos de instância.


6

Para lógica complexa dentro de uma classe, eu encontrei métodos estáticos privados úteis na criação de lógica isolada, na qual as entradas da instância são claramente definidas na assinatura do método e nenhum efeito colateral da instância pode ocorrer. Todas as saídas devem ser via valor de retorno ou parâmetros de saída / ref. Quebrando a lógica complexa em blocos de código sem efeitos colaterais pode melhorar a legibilidade do código e a confiança da equipe de desenvolvimento nele.

Por outro lado, pode levar a uma classe poluída por uma proliferação de métodos de utilidade. Como de costume, a nomeação lógica, a documentação e a aplicação consistente das convenções de codificação da equipe podem aliviar isso.


5

ReSharper não verifica a lógica. Ele verifica apenas se o método usa membros da instância. Se o método for privado e chamado apenas por (talvez apenas um) método de instância, isso é um sinal para permitir que ele seja um método de instância.


3

Se as funções forem compartilhadas em várias páginas, você também poderá colocá-las em uma classe de página base e, em seguida, todas as páginas asp.net usando essa funcionalidade serão herdadas (e as funções ainda poderão ser estáticas).


3

Tornar um método estático significa que você pode chamar o método de fora da classe sem antes criar uma instância dessa classe. Isso é útil ao trabalhar com objetos ou complementos de fornecedores de terceiros. Imagine se você tivesse que criar primeiro um objeto do console "con" antes de chamar con.Writeline ();


Java solicita que você crie uma instância de fábrica para criar o objeto Console antes de chamar con.Writeline ().
ScottMichaud

2

Ajuda a controlar a poluição do espaço para nome.


8
Como tornar um método estático ajuda a evitar a poluição do espaço para nome?
lockstock

11
Por experiência, agrupando métodos em classes com métodos estáticos, você evita a experiência de ter que prefixar todas as "sacolas" de funções soltas que podem entrar em conflito com outras funções internas da biblioteca ou. Com métodos estáticos, eles são efetivamente espaçados sob o nome da classe, ex. Class.a_core_function( .. )vsa_core_function( .. )
lintuxvi 08/12/16

0

Apenas minha tuppência: a adição de todos os métodos estáticos compartilhados a uma classe de utilitário permite adicionar

using static className; 

às instruções using, que tornam o código mais rápido para digitar e mais fácil de ler. Por exemplo, eu tenho um grande número do que seria chamado de "variáveis ​​globais" em algum código que herdei. Em vez de criar variáveis ​​globais em uma classe que era uma classe de instância, eu as defino como propriedades estáticas de uma classe global. Ele faz o trabalho, se estiver confuso, e eu posso apenas referenciar as propriedades pelo nome, porque eu tenho o namespace estático já mencionado.

Não tenho ideia se isso é uma boa prática ou não. Eu tenho muito a aprender sobre C # 4/5 e tanto código legado para refatorar que estou apenas tentando deixar as dicas de Roselyn me guiarem.

Joey


0

Espero que você já tenha entendido a diferença entre os métodos estático e de instância. Além disso, pode haver uma resposta longa e uma resposta curta. Respostas longas já são fornecidas por outros.

Minha resposta curta: Sim, você pode convertê-los em métodos estáticos, se o Resharper sugerir. Não há mal em fazê-lo. Em vez disso, ao tornar o método estático, você está realmente protegendo o método para que, desnecessariamente, não insira nenhum membro da instância nesse método. Dessa forma, você pode alcançar um princípio de POO " Minimize a acessibilidade de classes e membros ".

Quando o ReSharper sugere que um método de instância pode ser convertido em um método estático, ele está realmente dizendo: "Por que .. esse método está nesta classe, pois na verdade não está usando nenhum de seus estados?" Então, dá-lhe alimento para o pensamento. Então, é você quem pode perceber a necessidade de mover esse método para uma classe de utilidade estática ou não. De acordo com os princípios do SOLID, uma classe deve ter apenas uma responsabilidade central. Assim, você pode fazer uma limpeza melhor de suas aulas dessa maneira. Às vezes, você precisa de alguns métodos auxiliares, mesmo na classe de instância. Se for esse o caso, você pode mantê-los em um #region helper.

Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.