Il metodo può essere reso statico, ma dovrebbe?


366

A Resharper piace sottolineare più funzioni per pagina asp.net che potrebbero essere rese statiche. Mi aiuta se li faccio statici? Devo renderli statici e spostarli in una classe di utilità?


20
Resharper non sta davvero gridando "bassa coesione, bassa coesione"? è tempo di vedere se il metodo appartiene davvero a quella classe.
PK il

2
possibile duplicato dei vantaggi
dell'utilizzo di

Risposte:


245

Metodi statici rispetto ai metodi di istanza
10.2.5 I membri statici e di istanza delle specifiche del linguaggio C # spiegano la differenza. In generale, i metodi statici possono fornire un miglioramento delle prestazioni molto ridotto rispetto ai metodi di istanza, ma solo in situazioni alquanto estreme (vedere questa risposta per ulteriori dettagli al riguardo).

La regola CA1822 in FxCop o Code Analysis afferma:

"Dopo [contrassegnare i membri come statici], il compilatore emetterà siti di chiamata non virtuali a questi membri che impediranno un controllo in fase di esecuzione per ogni chiamata che assicuri che il puntatore dell'oggetto corrente sia non nullo. Ciò può comportare un guadagno misurabile delle prestazioni per il codice sensibile alle prestazioni. In alcuni casi, il mancato accesso all'istanza dell'oggetto corrente rappresenta un problema di correttezza. "

Classe di utilità
Non spostarli in una classe di utilità a meno che non abbia senso nella progettazione. Se il metodo statico si riferisce a un tipo particolare, come un ToRadians(double degrees)metodo si riferisce a una classe che rappresenta gli angoli, ha senso che quel metodo esista come un membro statico di quel tipo (nota, questo è un esempio contorto ai fini della dimostrazione).


2
> il compilatore emetterà siti di chiamata non virtuali a questi membri. In realtà è "il compilatore può emettere ...". Ricordo qualcosa sul compilatore C # che utilizza callvirt invece di call per aggirare alcuni potenziali bug.
Jonathan Allen,

24
L'ho tagliato e incollato direttamente da FxCop 1.36. Se FxCop è sbagliato, abbastanza giusto.
Jeff Yates,

5
@Maxim Non sono sicuro di apprezzare l'affermazione "stronzate"; modo piuttosto scortese di avvicinarsi agli estranei. Tuttavia, il punto sottostante è valido; Ho aggiornato un po 'le cose (era 9 anni fa, quindi non ricordo le fondamenta del mio reclamo originale).
Jeff Yates,

10
@Maxim Il tuo punto non è valido. Ti assicuro che non avevo una buona valutazione 9 anni fa. Apprezzo i commenti che evidenziano errori (o modifiche che li correggono), ma non essere scortese né porre aspettative irragionevoli sugli altri. Non chiamare qualcosa di "cazzate"; implica un intento di ingannare piuttosto che onesto all'errore di bontà o all'ignoranza. È maleducato. Mi offro volontario per aiutare qui e sembra davvero inutile quando viene trattato con mancanza di rispetto. Non dirmi da cosa offenderti: questa è la mia scelta, non la tua. Scopri come esprimere la tua opinione con rispetto e integrità. Grazie.
Jeff Yates,

2
@Maxim Mentre i delegati non vengono archiviati accanto a ciascuna istanza, ogni istanza di una classe senza stato occupa effettivamente un po 'di memoria sull'heap, che è inutile in termini di costi. Di solito i servizi di istanza non sono il percorso più rapido in un'applicazione, ma se l'applicazione finisce per costruire molti di questi oggetti, aumenterà la pressione GC che potrebbe essere evitata semplicemente usando metodi statici. L'affermazione originale del PO, che in situazioni estreme i metodi statici offrono un vantaggio in termini di prestazioni rispetto alle istanze senza stato, era opportunamente sfumata e valida.
Asad Saeeduddin,

259

Le prestazioni, l'inquinamento dello spazio dei nomi, ecc. Sono tutti secondari secondo me. Chiediti cosa è logico. Il metodo funziona logicamente su un'istanza del tipo o è correlato al tipo stesso? Se è quest'ultimo, rendilo un metodo statico. Spostalo in una classe di utilità solo se è correlato a un tipo che non è sotto il tuo controllo.

A volte ci sono metodi che logicamente agiscono su un'istanza, ma non capita di utilizzare una qualsiasi delle Stato dell'istanza ancora . Ad esempio, se stavi costruendo un file system e avessi ottenuto il concetto di directory, ma non lo avessi ancora implementato, potresti scrivere una proprietà che restituisca il tipo di oggetto del file system e sarebbe sempre "file" - ma è logicamente correlato all'istanza e quindi dovrebbe essere un metodo di istanza. Ciò è importante anche se si desidera rendere virtuale il metodo: l'implementazione particolare potrebbe non richiedere stato, ma le classi derivate potrebbero. (Ad esempio, chiedendo a una raccolta se è di sola lettura - potresti non aver ancora implementato un modulo di sola lettura di quella raccolta, ma è chiaramente una proprietà della raccolta stessa, non del tipo.)


1
Penso che una buona linter dovrebbe avere un'opzione per limitare il messaggio a metodi non virtuali, dal momento che sarebbe molto comune per un metodo di classe base non fare praticamente nulla. I metodi di sostituzione normalmente farebbero qualcosa, ma non sempre. A volte è utile avere una classe per qualcosa come un iEnumerable vuoto, i cui metodi essenzialmente ignorano l'istanza, ma dove l'istanza è richiesta per selezionare il metodo giusto da usare.
Supercat,

2
"A volte ci sono metodi che agiscono logicamente su un'istanza ma non usano ancora nessuno stato dell'istanza. Ad esempio" Mi è piaciuto il tuo uso di "ad esempio" in questa istanza.
PaulBinder,

56

Contrassegnare un metodo come staticall'interno di una classe rende ovvio che non utilizza alcun membro di istanza, il che può essere utile sapere quando si scorre il codice.

Non devi necessariamente spostarlo in un'altra classe a meno che non sia pensato per essere condiviso da un'altra classe che è strettamente associata, dal punto di vista concettuale.


22

Sono sicuro che questo non sta accadendo nel tuo caso, ma un "cattivo odore" che ho visto in alcuni codici che ho dovuto soffrire per aver usato un sacco di metodi statici.

Sfortunatamente, si trattava di metodi statici che presupponevano un particolare stato dell'applicazione. (perché certo, avremo un solo utente per applicazione! Perché non fare in modo che la classe User tenga traccia di ciò nelle variabili statiche?) Erano modi glorificati per accedere alle variabili globali. Avevano anche costruttori statici (!), Che sono quasi sempre una cattiva idea. (So ​​che ci sono un paio di eccezioni ragionevoli).

Tuttavia, i metodi statici sono piuttosto utili quando escludono la logica di dominio che in realtà non dipende dallo stato di un'istanza dell'oggetto. Possono rendere il tuo codice molto più leggibile.

Assicurati solo di metterli nel posto giusto. I metodi statici stanno manipolando in modo intrusivo lo stato interno di altri oggetti? Si può sostenere che il loro comportamento appartiene invece a una di quelle classi? Se non stai separando correttamente le preoccupazioni, potresti avere mal di testa in seguito.


4
Il tuo problema è con campi / proprietà statici, non metodi statici.
Asad Saeeduddin,

10

Questo è interessante leggi:

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

ReSharper non sta effettivamente suggerendo di rendere statico il metodo. Dovresti chiederti perché quel metodo è in quella classe invece di, diciamo, una delle classi che appare nella sua firma ...

ma ecco cosa dice documentaion resharper: http://confluence.jetbrains.net/display/ReSharper/Member+can+be+made+static


2
Penso che questo punto sia sottovalutato. Ciò che lo strumento ti sta davvero dicendo è che il metodo funziona solo su membri di altre classi. Se è una sorta di oggetto comando (o "caso d'uso" o "interattore"), la cui responsabilità è manipolare altri oggetti, va bene. Tuttavia, se manipola solo un'altra classe che suona molto come Feature Envy .
Greg,

9

Giusto per aggiungere al di @ Jason Vero risposta , è importante rendersi conto che solo mettendo 'statica' su un metodo non garantisce che il metodo sarà 'pura'. Sarà apolide rispetto alla classe in cui viene dichiarato, ma potrebbe anche accedere ad altri oggetti "statici" con stato (configurazione dell'applicazione ecc.), Questo potrebbe non essere sempre una cosa negativa, ma uno dei motivi per cui Personalmente tendo a preferire metodi statici quando posso che se sono puri, puoi testarli e ragionarli in modo isolato, senza doversi preoccupare dello stato circostante.


6

Dovresti fare ciò che è più leggibile e intuitivo in un determinato scenario.

L'argomento delle prestazioni non è valido tranne nelle situazioni più estreme poiché l'unica cosa che sta effettivamente accadendo è che un parametro aggiuntivo ( this) viene inserito nello stack per i metodi di istanza.


6

Per la logica complessa all'interno di una classe, ho trovato utili metodi statici privati ​​nella creazione di una logica isolata, in cui gli input dell'istanza sono chiaramente definiti nella firma del metodo e non possono verificarsi effetti collaterali dell'istanza. Tutte le uscite devono essere tramite valore di ritorno o parametri out / ref. Abbattere la logica complessa in blocchi di codice privi di effetti collaterali può migliorare la leggibilità del codice e la fiducia del team di sviluppo in esso.

D'altra parte può portare a una classe inquinata da una proliferazione di metodi di utilità. Come al solito, la denominazione logica, la documentazione e l'applicazione coerente delle convenzioni di codifica del team possono alleviarlo.


5

ReSharper non controlla la logica. Verifica solo se il metodo utilizza membri dell'istanza. Se il metodo è privato e chiamato solo da (forse solo uno) metodi di istanza, questo è un segno per lasciarlo un metodo di istanza.


3

Se le funzioni sono condivise su più pagine, puoi anche inserirle in una classe di pagine di base e quindi avere tutte le pagine asp.net che utilizzano quella funzionalità ereditata da essa (e le funzioni potrebbero anche essere statiche).


3

Rendere statico un metodo significa che puoi chiamare il metodo dall'esterno della classe senza prima creare un'istanza di quella classe. Ciò è utile quando si lavora con oggetti o componenti aggiuntivi di fornitori di terze parti. Immagina di dover prima creare un oggetto console "con" prima di chiamare con.Writeline ();


Java vorrebbe creare un'istanza di fabbrica per creare l'oggetto Console prima di chiamare con.Writeline ().
ScottMichaud,

2

Aiuta a controllare l'inquinamento dello spazio dei nomi.


8
In che modo rendere statico un metodo aiuta a evitare l'inquinamento dello spazio dei nomi?
Lockstock

1
Dall'esperienza, raggruppando i metodi in classi con metodi statici, stai evitando l'esperienza di dover anteporre a tutto il "grab bag" di funzioni libere che potrebbero entrare in conflitto con altre librerie o funzioni incorporate. Con i metodi statici, sono effettivamente spaziati sotto il Nome classe, ad es. Class.a_core_function( .. )vsa_core_function( .. )
lintuxvi,

0

Solo la mia tuppenza: l'aggiunta di tutti i metodi statici condivisi a una classe di utilità consente di aggiungere

using static className; 

alle tue istruzioni using, che rendono il codice più veloce da digitare e più facile da leggere. Ad esempio, ho un gran numero di quelle che verrebbero chiamate "variabili globali" in un codice che ho ereditato. Invece di creare variabili globali in una classe che era una classe di istanza, le ho impostate tutte come proprietà statiche di una classe globale. Fa il lavoro, anche se in modo disordinato, e posso solo fare riferimento alle proprietà per nome perché ho già lo spazio dei nomi statico a cui si fa riferimento.

Non ho idea se questa è una buona pratica o no. Ho così tanto da imparare su C # 4/5 e così tanto codice legacy da refactoring che sto solo cercando di lasciarmi guidare dai suggerimenti di Roselyn.

Joey


0

Spero che tu abbia già capito la differenza tra i metodi statici e quelli di istanza. Inoltre, può esserci una risposta lunga e una risposta breve. Le risposte lunghe sono già fornite da altri.

La mia breve risposta: Sì, puoi convertirli in metodi statici se Resharper suggerisce. Non c'è nulla di male nel farlo. Piuttosto, rendendo statico il metodo, stai effettivamente proteggendo il metodo in modo che, inutilmente, non scivoli alcun membro dell'istanza su quel metodo. In questo modo, è possibile ottenere un principio OOP " Ridurre al minimo l'accessibilità di classi e membri ".

Quando ReSharper suggerisce che un metodo di istanza può essere convertito in un metodo statico, in realtà ti dice: "Perché il .. questo metodo si trova in questa classe in quanto non sta effettivamente utilizzando nessuno dei suoi stati?" Quindi, ti dà spunti di riflessione. Quindi, sei tu che puoi capire la necessità di spostare quel metodo in una classe di utilità statica o meno. Secondo i principi SOLID, una classe dovrebbe avere una sola responsabilità fondamentale. Quindi, puoi fare una migliore pulizia delle tue lezioni in quel modo. A volte, hai bisogno di alcuni metodi di supporto anche nella tua classe di istanza. In tal caso, puoi tenerli all'interno di un helper #region.

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.