Os métodos C # que * podem * ser estáticos devem ser estáticos? [fechadas]

103

Os métodos C # que podem ser estáticos devem ser estáticos?

Estávamos discutindo isso hoje e estou meio em cima do muro. Imagine que você tem um método longo do qual refatora algumas linhas. O novo método provavelmente pega algumas variáveis ​​locais do método pai e retorna um valor. Isso significa que pode ser estático.

A questão é: deve ser estático? Não é estático por design ou escolha, simplesmente por sua natureza, pois não faz referência a nenhum valor de instância.

Bernhard Hofmann
fonte
1
Duplicata razoavelmente exata de stackoverflow.com/questions/169378/…
JasonTrue,
41
"bastante exato" é um oxímoro
Matt Briggs
1
Resharper , a ferramenta de ferramentas do Visual Studio, diz que sim! :-)
Rebecca
@Junto Talvez na sua versão, mas a minha diz que pode ser tornada estática ...
Robbie Dee

Respostas:

59

Depende. Na verdade, existem 2 tipos de métodos estáticos:

  1. Métodos que são estáticos porque PODEM ser
  2. Métodos que são estáticos porque TÊM que ser

Em uma base de código de tamanho pequeno a médio, você pode realmente tratar os dois métodos de forma intercambiável.

Se você tem um método que está na primeira categoria (pode ser estático) e precisa alterá-lo para acessar o estado da classe, é relativamente simples descobrir se é possível transformar o método estático em um método de instância.

Em uma grande base de código, no entanto, o grande número de sites de chamada pode tornar a pesquisa para ver se é possível converter um método estático em um não estático muito caro. Muitas vezes as pessoas verão o número de ligações e dirão "ok ... é melhor não mudar esse método, mas sim criar um novo que faça o que eu preciso".

Isso pode resultar em:

  1. Muita duplicação de código
  2. Uma explosão no número de argumentos do método

Essas duas coisas são ruins.

Portanto, meu conselho seria que, se você tiver uma base de código acima de 200K LOC, eu só tornaria os métodos estáticos se eles fossem métodos estáticos obrigatórios.

A refatoração de não estático para estático é relativamente fácil (basta adicionar uma palavra-chave), então se você quiser transformar um pode ser estático em um estático real mais tarde (quando precisar da funcionalidade fora de uma instância), você pode. No entanto, a refatoração inversa, transformando um método can-be-static em um método de instância é MUITO mais caro.

Com grandes bases de código, é melhor errar pelo lado da facilidade de extensão do que pelo lado da pureza idealógica.

Portanto, para grandes projetos, não torne as coisas estáticas, a menos que você precise que elas o sejam. Para pequenos projetos, basta fazer o que você mais gosta.

Scott Wisniewski
fonte
43

Eu não o tornaria um membro público estático dessa classe . O motivo é que torná-lo público estático é dizer algo sobre o tipo da classe: não apenas que "esse tipo sabe como fazer esse comportamento", mas também "é responsabilidade desse tipo realizar esse comportamento". E as probabilidades são de que o comportamento não tenha mais qualquer relação real com o tipo maior.

Isso não significa que eu não o tornaria estático, no entanto. Pergunte a si mesmo: o novo método poderia logicamente pertencer a outro lugar? Se você puder responder "sim" a isso, provavelmente deseja torná-lo estático (e movê-lo também). Mesmo que isso não seja verdade, você ainda pode torná-lo estático. Só não marque public.

Por uma questão de conveniência, você pode pelo menos marcá-lo internal. Isso normalmente evita a necessidade de mover o método se você não tiver acesso fácil a um tipo mais apropriado, mas ainda o deixa acessível onde necessário de uma maneira que não apareça como parte da interface pública para usuários de sua classe .

Joel Coehoorn
fonte
6
Acordado. Eu geralmente torno o método "privado estático" em um caso como este.
Harpo de
6
Eu também não assumiria estática privada. O principal é se perguntar: esse método se encaixa logicamente como parte desse tipo ou está aqui apenas por uma questão de conveniência? Se for o último, pode caber melhor em outro lugar?
Joel Coehoorn
1
Como: "o novo método poderia logicamente pertencer a outro lugar" - a pista é que ele não depende do estado local, talvez o tipo de retorno esteja onde ele pertence?
AndyM
20

Não necessariamente.

Mover os métodos públicos de estáticos para não estáticos é uma alteração importante e exigiria alterações para todos os chamadores ou consumidores. Se um método parece ser um método de instância, mas acontece de não usar nenhum membro de instância, eu sugeriria torná-lo um método de instância como uma medida de segurança futura.

Michael
fonte
Acho que ele está se referindo principalmente a métodos privados
George Mauer,
@Ray - Certo, isso só se aplica a membros não particulares. Eu atualizei minha resposta para refletir isso.
Michael,
Minha opinião exatamente - só porque você pode fazer algo estático, não significa que você precisa ou deveria ...
marc_s
Então, o que você faria para métodos privados que poderiam se tornar estáticos?
Ray,
@Ray - Provavelmente deixe como está até que eu tenha uma razão boa o suficiente para passar para a estática.
Michael,
13

Sim. A razão "pode ​​ser estático" é que não opera no estado do objeto sobre o qual é chamado. Portanto, não é um método de instância, mas um método de classe. Se ele puder fazer o que precisa sem nunca acessar os dados da instância, então deve ser estático.

JP Alioto
fonte
11

Sim, deveria. Existem várias métricas de acoplamento que medem como sua classe depende de outras coisas, como outras classes, métodos, etc. Tornar métodos estáticos é uma maneira de manter o grau de acoplamento baixo, uma vez que você pode ter certeza de que um método estático não faz referência a nenhum membros.

Jabe
fonte
7
Não necessariamente. Um método estático não acessa informações de instância, nenhum membro, como você disse, mas é capaz de interagir com outras classes assim como outro método comum. Ser estático não significa necessariamente que o acoplamento seja reduzido. No entanto, eu entendi seu ponto.
Victor Rodrigues
Em vez disso, a estática realmente aumenta o acoplamento, porque você está limitado exatamente a esse método estático, nenhuma maneira de ignorá-lo, por exemplo, e, portanto, nenhuma maneira de mudar o comportamento.
HimBromBeere
8

Acho que ficaria um pouco mais legível se você marcasse como estático ... Então, alguém que aparecer saberia que não faz referência a nenhuma variável de instância sem ter que ler a função inteira ...

Jason Punyon
fonte
6

Pessoalmente, sou um grande fã da apatridia. Seu método precisa acessar o estado da classe? Se a resposta for não (e provavelmente não, caso contrário, você não consideraria torná-lo um método estático), então sim, vá em frente.

Nenhum acesso ao estado é menos dor de cabeça. Assim como é uma boa ideia ocultar membros privados que não são necessários para outras classes, é uma boa ideia ocultar o estado dos membros que não precisam dele. Acesso reduzido pode significar menos bugs. Além disso, torna o encadeamento mais fácil, pois é muito mais fácil manter os membros estáticos protegidos contra encadeamentos. Há também uma consideração de desempenho, pois o tempo de execução não precisa passar uma referência a isso como um parâmetro para métodos estáticos.

Obviamente, a desvantagem é que, se você descobrir que seu método anteriormente estático terá que acessar o estado por algum motivo, será necessário alterá-lo. Agora eu entendo que isso pode ser um problema para APIs públicas, portanto, se este for um método público em uma classe pública, talvez você deva pensar um pouco sobre as implicações disso. Ainda assim, nunca enfrentei uma situação no mundo real em que isso realmente causasse um problema, mas talvez eu só tenha sorte.

Então, sim, vá em frente, por todos os meios.

Tamas Czinege
fonte
1
Um método estático ainda pode ter acesso ao estado. Ele apenas obtém o estado do objeto passado para ele. Por outro lado, os campos de instância não contêm necessariamente estado mutável.
Jørgen Fogh
6

Métodos estáticos são mais rápidos do que os não estáticos, então sim, eles devem ser estáticos se puderem e não há nenhuma razão especial para deixá-los não estáticos .

Agnieszka
fonte
3
Isso é tecnicamente verdade, mas não em um sentido material real. A diferença entre estático / não será muito, muito raramente um fator de desempenho.
Foredecker
22
-1: Otimização prematura do livro didático. A velocidade certamente não deve ser o primeiro critério ao decidir estático versus não estático para o caso geral.
Não tenho certeza,
2
Concordo com Não tenho certeza, esta deve ser sua última razão para considerar estática versus não.
Samuel,
5
Meu ponto é que a velocidade é um dos motivos mais pobres que você pode ter para decidir se uma função é estática ou não estática em 99% dos casos. Existem considerações muito mais importantes quando se trata de design OO que outras postagens elaboram.
Não tenho certeza de
2
@agnieszka: O motivo especial de geralmente usar métodos de instância em vez de métodos estáticos é o estado. Se você deixar seus métodos estáticos, em uma aplicação complexa introduzirá bugs que o farão arrancar os cabelos. Pense em modificar o estado global, condições de corrida, segurança de thread etc.
Sandor Davidhazi,
5

Estou surpreso que tão poucos estejam mencionando o encapsulamento aqui de fato. Um método de instância terá automaticamente acesso a todos os campos, propriedades e métodos privados (instância). Além de todos os protegidos herdados das classes base.

Ao escrever código, você deve escrevê-lo de forma que exponha o mínimo possível e também para que tenha acesso ao mínimo possível.

Então, sim, pode ser importante tornar seu código mais rápido, o que aconteceria se você estivesse tornando seus métodos estáticos, mas geralmente mais importante do que tornar seu código o mais incapaz de criar bugs possível também. Uma maneira de conseguir isso é fazer com que seu código tenha acesso ao mínimo possível de "coisas privadas".

Isso pode parecer irrelevante à primeira vista, pois o OP está obviamente falando sobre refatoração que não pode dar errado neste cenário e criar novos bugs, no entanto, esse código refatorado deve ser mantido no futuro e modificado, o que faz com que seu código tenha um ataque maior " superfície "em relação a novos bugs se ele tiver acesso a membros de instâncias privadas. Portanto, em geral, acho que a conclusão aqui é que "sim, principalmente seus métodos devem ser estáticos", a menos que haja quaisquer outras razões para não tê-los estáticos. E isso simplesmente porque é "melhor uso de encapsulamento e ocultação de dados e cria um código 'mais seguro'" ...

Thomas Hansen
fonte
4

Tornar algo estático só porque você pode não é uma boa ideia. Os métodos estáticos devem ser estáticos devido ao seu design, não por acaso.

Como Michael disse, alterar isso posteriormente interromperá o código que o está usando.

Dito isso, parece que você está criando uma função de utilidade privada para a classe que é, na verdade, estática por design.

17 de 26
fonte
4

Se você foi capaz de refatorar algumas linhas e o método resultante pode ser estático, é provavelmente uma indicação de que as linhas que você puxou desse método não pertencem à classe contida, e você deve considerar movê-las para sua própria classe.

Chris Shaffer
fonte
2

Pessoalmente, eu não teria escolha a não ser torná-lo estático. Neste caso, o Resharper emite um aviso e nosso PM tem uma regra "Sem avisos do Resharper".

Brincalhão
fonte
1
Você pode alterar as configurações do ReSharper: P
Bernhard Hofmann,
1
Se fosse tão fácil, não teríamos desgaste do Resharper ... nunca :)
Prankster,
1

Depende, mas geralmente eu não torno esses métodos estáticos. O código está sempre mudando e talvez um dia eu queira tornar essa função virtual e substituí-la em uma subclasse. Ou talvez algum dia ele precise fazer referência a variáveis ​​de instância. Será mais difícil fazer essas alterações se cada site de chamada tiver que ser alterado.

Brian Ensink
fonte
Sim, mas se algum dia você precisar fazer isso, você sempre pode torná-lo não estático. Ou eu estou esquecendo de alguma coisa?
Ray,
1
@Ray - Cubro isso em minha resposta. estático para não estático é uma alteração significativa, portanto, todos os consumidores precisam ser modificados. Não é grande coisa para um programa pequeno, mas se for uma biblioteca para ser consumida por outros, isso deve ser levado em consideração.
Michael,
Todos os sites de chamada devem ser alterados de uma chamada de método estático para uma chamada de função de membro.
Brian Ensink,
Desculpe, você adicionou isso depois do meu comentário. Em minha mente, eu estava pensando em métodos privados, mas esse é um ponto válido para métodos públicos.
Ray,
... ou algum dia você pode jogá-lo fora. esses argumentos não são bons o suficiente para que eu torne um método não estático.
agnieszka,
1

Eu sugiro que a melhor maneira de pensar sobre isso é: se você precisa de um método de classe que precise ser chamado quando nenhuma instância da classe for instanciada ou manter algum tipo de estado global, estático é uma boa ideia. Mas, em geral, sugiro que você prefira tornar os membros não estáticos.

Foredecker
fonte
1

Você deve pensar sobre seus métodos e classes:

  • Como você vai usá-los?
  • Você precisa de muito acesso a eles de diferentes níveis de seu código?
  • Este é um método / classe que posso usar em quase todos os projetos imagináveis.

Se os dois últimos forem 'sim', então seu método / classe provavelmente deve ser estático.

O exemplo mais usado provavelmente é a Mathclasse. Todas as principais linguagens OO o possuem e todos os métodos são estáticos. Porque você precisa ser capaz de usá-los em qualquer lugar, a qualquer hora, sem criar uma instância.

Outro bom exemplo é o Reverse()método em C #.
Este é um método estático na Arrayclasse. Ele inverte a ordem do seu array.

Código:

public static void Reverse(Array array)

Ele nem retorna nada, seu array é invertido, porque todos os arrays são instâncias da classe Array.

KdgDev
fonte
A matemática é um mau exemplo. Acho que é melhor: newnumber = number.round (2) do que newnumber = Math.round (number)
graffic de
3
A classe Math é o exemplo perfeito de uso de classes estáticas. Este é o assunto deste tópico, não sobre como você prefere arredondar números ...
KdgDev
1

Contanto que você torne o novo método private static , não é uma alteração significativa. Na verdade, FxCop inclui essa orientação como uma de suas regras ( http://msdn.microsoft.com/en-us/library/ms245046(VS.80).aspx ), com as seguintes informações:

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 para cada chamada que garante que o ponteiro do objeto atual é 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 em acessar a instância do objeto atual representa um problema de correção.

Dito isso, o primeiro comentário de David Kean resume mais sucintamente as preocupações, dizendo que isso é mais sobre estar correto do que sobre o ganho de desempenho:

Embora essa regra seja classificada como um problema de desempenho, a melhoria de desempenho de tornar um método estático é de apenas cerca de 1%. Em vez disso, é mais um problema de correção que poderia indicar um incompleto ou um bug no membro por sua falha em usar outros membros da instância. Marcar um método como estático ( Compartilhado no Visual Basic) deixa claro sua intenção de não tocar no estado da instância.

Scott Dorman
fonte
1

Eu definitivamente transformaria tudo o que puder em estático por um motivo diferente:

Funções estáticas, quando JIT'd, são chamadas sem um parâmetro "this". Isso significa, por exemplo, que uma função não estática de 3 parâmetros (método membro) é enviada com 4 parâmetros na pilha.

A mesma função compilada como uma função estática seria chamada com 3 parâmetros. Isso pode liberar registros para o JIT e conservar espaço na pilha ...

prejudicial ao menino
fonte
1

Estou no campo "apenas tornar estáticos métodos privados". Tornar um método público pode introduzir um acoplamento que você não deseja e pode diminuir a testabilidade: você não pode criar um método estático público.

Se você quiser testar a unidade de um método que usa um método estático público, acabará testando o método estático também, que pode não ser o que você deseja.

Lennaert
fonte
1

Métodos inerentemente estáticos que, por algum motivo, são tornados não estáticos são simplesmente irritantes. A saber:

Eu ligo para meu banco e peço meu saldo.
Eles pedem o número da minha conta.
Justo. Método de instância.

Ligo para o meu banco e peço o endereço de correspondência.
Eles pedem o número da minha conta.
WTF? Falha - deveria ser um método estático.

IJ Kennedy
fonte
1
E se clientes diferentes forem atendidos por agências diferentes? O envio de correspondência para a sede do banco pode levá-la à agência adequada, eventualmente, mas isso não significa que um cliente não seria melhor atendido usando o endereço da agência específica que o atende.
supercat de
0

Eu vejo isso geralmente de uma perspectiva funcional de funções puras. Precisa ser um método de instância? Caso contrário, você pode se beneficiar forçando o usuário a passar as variáveis ​​e não mutilar o estado da instância atual. (Bem, você ainda poderia mutilar o estado, mas o objetivo é, por design, não fazer isso.) Geralmente, projeto métodos de instância como membros públicos e faço o meu melhor para tornar os membros privados estáticos. Se necessário (você pode então extraí-los mais facilmente para outras classes posteriormente.


fonte
-1

Nesses casos, tendo a mover o método para uma biblioteca estática ou utils, então não misturo o conceito de "objeto" com o conceito de "classe"

Jhonny D. Cano -Leftware-
fonte