Em teoria, um método estático deve ter um desempenho ligeiramente melhor do que um método de instância, todas as outras coisas sendo iguais, por causa do this
parâmetro oculto extra .
Na prática, isso faz tão pouca diferença que ficará oculto no ruído de várias decisões do compilador. (Conseqüentemente, duas pessoas poderiam "provar" uma melhor do que a outra com resultados discordantes). Até porque o this
é normalmente passado em um registro e freqüentemente está naquele registro para começar.
Este último ponto significa que, em teoria, devemos esperar que um método estático que pega um objeto como parâmetro e faz algo com ele seja ligeiramente menos bom do que o equivalente como uma instância nesse mesmo objeto. Mais uma vez, porém, a diferença é tão pequena que, se você tentar medi-la, provavelmente acabará medindo alguma outra decisão do compilador. (Especialmente porque a probabilidade de essa referência estar em um registro o tempo todo também é bastante alta).
As diferenças reais de desempenho se resumem a se você tem objetos artificialmente na memória para fazer algo que deveria ser naturalmente estático, ou se você está enrolando cadeias de passagem de objetos de maneiras complicadas para fazer o que deveria ser naturalmente uma instância.
Portanto, para o número 1. Quando manter o estado não é uma preocupação, é sempre melhor ser estático, porque é para isso que serve a estática . Não é uma preocupação de desempenho, embora haja uma regra geral de jogar bem com otimizações de compilador - é mais provável que alguém se esforce para otimizar casos que surgem com uso normal do que aqueles que surgem com uso estranho.
Número 2. Não faz diferença. Há uma certa quantia de custo por classe para cada membro em termos de quantos metadados existem, quanto código existe no arquivo DLL ou EXE real e quanto código modificado haverá. É o mesmo, seja instância ou estático.
Com o item 3, this
é como this
faz. No entanto, observe:
O this
parâmetro é passado em um determinado registro. Ao chamar um método de instância dentro da mesma classe, ele provavelmente já estará naquele registro (a menos que tenha sido armazenado e o registro usado por algum motivo) e, portanto, não há nenhuma ação necessária para definir o this
que ele precisa ser definido para . Isso se aplica até certo ponto, por exemplo, os dois primeiros parâmetros do método sendo os dois primeiros parâmetros de uma chamada que ele faz.
Como ficará claro que this
não é nulo, isso pode ser usado para otimizar chamadas em alguns casos.
Uma vez que ficará claro que this
não é nulo, isso pode tornar as chamadas de método embutidas mais eficientes novamente, já que o código produzido para falsificar a chamada do método pode omitir algumas verificações de nulo que podem precisar de qualquer maneira.
Dito isso, cheques nulos são baratos!
É importante notar que métodos estáticos genéricos atuando em um objeto, em vez de métodos de instância, podem reduzir alguns dos custos discutidos em http://joeduffyblog.com/2011/10/23/on-generics-and-some-of- the-associated-overheads / no caso em que determinado estático não é chamado para um determinado tipo. Como ele coloca, "Como um aparte, os métodos de extensão são uma ótima maneira de tornar as abstrações genéricas mais pagas".
No entanto, observe que isso se refere apenas à instanciação de outros tipos usados pelo método, que de outra forma não existem. Como tal, ele realmente não se aplica a muitos casos (algum outro método de instância usou esse tipo, algum outro código em outro lugar usou esse tipo).
Resumo:
- Principalmente os custos de desempenho de instância vs estático estão abaixo de insignificantes.
- Os custos geralmente virão quando você abusar da estática, por exemplo, ou vice-versa. Se você não fizer parte de sua decisão entre estático e instância, é mais provável que obtenha o resultado correto.
- Existem raros casos em que métodos genéricos estáticos em outro tipo resultam em menos tipos sendo criados do que métodos genéricos de instância, o que pode fazer com que às vezes tenha um pequeno benefício por ser raramente usado (e "raramente" se refere a quais tipos são usados no tempo de vida do aplicativo, não com que frequência é chamado). Depois de entender o que ele está falando naquele artigo, você verá que é 100% irrelevante para a maioria das decisões estáticas versus instâncias. Edit: E na maior parte só tem esse custo com ngen, não com código jitting.
Edit: Uma nota sobre o quão baratos são os cheques nulos (que afirmei acima). A maioria das verificações de nulo no .NET não verifica nada em relação a nulo, em vez disso, continua o que faria com a suposição de que funcionará e, se ocorrer uma exceção de acesso, ela será transformada em um NullReferenceException
. Como tal, principalmente quando conceitualmente o código C # envolve uma verificação de nulo porque está acessando um membro da instância, o custo se for bem-sucedido será, na verdade, zero. Uma exceção seriam algumas chamadas inline, (porque eles querem se comportar como se tivessem chamado um membro da instância) e eles apenas acessam um campo para acionar o mesmo comportamento, então eles também são muito baratos e ainda podem ser deixados de fora de qualquer maneira (por exemplo, se a primeira etapa do método envolvia acessar um campo como ele era).