I metodi C # che * possono * essere statici dovrebbero essere statici? [chiuso]


103

I metodi C # che possono essere statici dovrebbero essere statici?

Ne stavamo discutendo oggi e sono un po 'sul recinto. Immagina di avere un metodo lungo da cui eseguire il refactoring di poche righe. Il nuovo metodo probabilmente prende alcune variabili locali dal metodo genitore e restituisce un valore. Ciò significa che potrebbe essere statico.

La domanda è: dovrebbe essere statica? Non è statico per progettazione o scelta, semplicemente per sua natura in quanto non fa riferimento a valori di istanza.


1
Abbastanza esatto duplicato di stackoverflow.com/questions/169378/...
JasonTrue

41
"abbastanza esatto" è un ossimoro
Matt Briggs,

1
Resharper , lo strumento degli strumenti di Visual Studio, dice di sì! :-)
Rebecca

@Junto Forse nella tua versione, ma la mia dice che può essere resa statica ...
Robbie Dee

Risposte:


59

Dipende. Esistono davvero 2 tipi di metodi statici:

  1. Metodi statici perché POSSONO esserlo
  2. Metodi statici perché DEVONO esserlo

In una base di codice di piccole e medie dimensioni puoi davvero trattare i due metodi in modo intercambiabile.

Se hai un metodo che si trova nella prima categoria (can-be-static), e devi cambiarlo per accedere allo stato della classe, è relativamente semplice capire se è possibile trasformare il metodo statico in un metodo di istanza.

In una grande base di codice, tuttavia, il numero di siti di chiamata potrebbe rendere la ricerca per vedere se è possibile convertire un metodo statico in uno non statico troppo costoso. Molte volte le persone vedranno il numero di chiamate e diranno "ok ... meglio non cambiare questo metodo, ma crearne uno nuovo che fa quello che mi serve".

Ciò può comportare:

  1. Molta duplicazione del codice
  2. Un'esplosione nel numero di argomenti del metodo

Entrambe queste cose sono cattive.

Quindi, il mio consiglio è che se si dispone di una base di codice superiore a 200K LOC, renderei i metodi statici solo se sono metodi statici.

Il refactoring da non statico a statico è relativamente facile (basta aggiungere una parola chiave), quindi se vuoi trasformare un can-be-static in uno statico effettivo in un secondo momento (quando hai bisogno della sua funzionalità al di fuori di un'istanza) puoi farlo. Tuttavia, il refactoring inverso, che trasforma un can-be-static in un metodo di istanza, è MOLTO più costoso.

Con basi di codice di grandi dimensioni è meglio sbagliare sul lato della facilità di estensione, piuttosto che sul lato della purezza dell'idea logica.

Quindi, per i grandi progetti non rendere le cose statiche a meno che non sia necessario che lo siano. Per piccoli progetti, fai quello che ti piace di più.


43

Vorrei non farne un pubblico membro statico di quella classe . Il motivo è che renderlo statico pubblico significa dire qualcosa sul tipo della classe: non solo "questo tipo sa come fare questo comportamento", ma anche "è responsabilità di questo tipo eseguire questo comportamento". E le probabilità sono che il comportamento non abbia più alcuna relazione reale con il tipo più grande.

Ciò non significa che non lo renderei affatto statico, però. Chiediti questo: il nuovo metodo potrebbe logicamente appartenere altrove? Se puoi rispondere "sì" a questo, probabilmente vuoi renderlo statico (e anche spostarlo). Anche se non è vero, potresti comunque renderlo statico. Basta non contrassegnarlo public.

Per comodità, potresti almeno contrassegnarlo internal. Questo in genere evita di dover spostare il metodo se non hai un facile accesso a un tipo più appropriato, ma lo lascia comunque accessibile dove necessario in modo che non venga mostrato come parte dell'interfaccia pubblica agli utenti della tua classe .


6
Concordato. Generalmente rendo il metodo "statico privato" in un caso come questo.
arpione

6
Non darei nemmeno per scontato statico privato. La cosa principale è chiedersi: questo metodo si adatta logicamente a questo tipo, o è solo qui per comodità? In quest'ultimo caso, potrebbe adattarsi meglio da qualche altra parte?
Joel Coehoorn

1
Come: "il nuovo metodo potrebbe appartenere logicamente altrove" - ​​l'indizio è che non si basa sullo stato locale, forse il tipo di ritorno è quello a cui appartiene?
AndyM

20

Non necessariamente.

Spostare i metodi pubblici da statici a non statici è un cambiamento fondamentale e richiederebbe modifiche a tutti i chiamanti o consumatori. Se un metodo sembra un metodo di istanza, ma capita di non utilizzare alcun membro di istanza, suggerirei di renderlo un metodo di istanza come misura della verifica futura.


Penso che si riferisca principalmente a metodi privati
George Mauer,

@Ray - Giusto, questo si applica solo ai membri non privati. Ho aggiornato la mia risposta per riflettere questo.
Michael

I miei pensieri esattamente - solo perché si potrebbe fare qualcosa di statico non significa che devi o dovrebbe .....
marc_s

Quindi cosa faresti per i metodi privati ​​che potrebbero essere resi statici?
Ray

@ Ray - Probabilmente me ne vado così com'è finché non avrò ragioni sufficienti per passare allo statico.
Michael

13

Sì. Il motivo per cui "può essere statico" è che non opera sullo stato dell'oggetto su cui è chiamato. Pertanto non è un metodo di istanza, ma un metodo di classe. Se può fare ciò che deve fare senza mai accedere ai dati per l'istanza, allora dovrebbe essere statico.


11

Sì, dovrebbe. Esistono varie metriche di accoppiamento che misurano come la tua classe dipende da altre cose, come altre classi, metodi, ecc. Rendere statici i metodi è un modo per mantenere basso il grado di accoppiamento, poiché puoi essere certo che un metodo statico non fa riferimento membri.


7
Non necessariamente. Un metodo statico non accederà alle informazioni sull'istanza, nessun membro, come hai detto tu, ma è in grado di interagire con altre classi così come un altro metodo comune. Essere statici non significa necessariamente ridurre l'accoppiamento. Tuttavia, ho capito il tuo punto.
Victor Rodrigues

Invece lo statico aumenta effettivamente l' accoppiamento, perché sei limitato esattamente a quel metodo statico, nessun modo per ignorarlo per esempio e quindi nessun modo per cambiare il comportamento.
HimBromBeere

8

Penso che lo renderebbe un po 'più leggibile se lo contrassegni come statico ... Allora qualcuno che arriva saprebbe che non fa riferimento a variabili di istanza senza dover leggere l'intera funzione ...


6

Personalmente, sono un grande fan dell'apolidia. Il tuo metodo ha bisogno di accedere allo stato della classe? Se la risposta è no (e probabilmente è no, altrimenti non prenderesti in considerazione l'idea di renderlo un metodo statico), allora sì, fallo.

Nessun accesso allo stato è meno mal di testa. Così come è una buona idea nascondere i membri privati ​​che non sono necessari ad altre classi, è una buona idea nascondere lo stato ai membri che non ne hanno bisogno. Un accesso ridotto può significare meno bug. Inoltre, rende più facile il threading in quanto è molto più facile mantenere i membri statici thread-safe. C'è anche una considerazione sulle prestazioni poiché il runtime non ha bisogno di passare un riferimento a questo come parametro per i metodi statici.

Ovviamente lo svantaggio è che se scopri che il tuo metodo precedentemente statico dovrà accedere allo stato per qualche motivo, allora devi cambiarlo. Ora capisco che questo può essere un problema per le API pubbliche, quindi se questo è un metodo pubblico in una classe pubblica, forse dovresti pensare un po 'alle implicazioni di questo. Tuttavia, non ho mai affrontato una situazione nel mondo reale in cui ciò ha effettivamente causato un problema, ma forse sono solo fortunato.

Quindi sì, provaci, con tutti i mezzi.


1
Un metodo statico può ancora avere accesso allo stato. Ottiene solo lo stato dall'oggetto che gli è stato passato. Al contrario, i campi istanza non contengono necessariamente uno stato mutabile.
Jørgen Fogh

6

I metodi statici sono più veloci di quelli non statici, quindi sì, dovrebbero essere statici se possono e non c'è motivo speciale per lasciarli non statici .


3
Questo è tecnicamente vero, ma non in un vero senso materiale. La differenza tra statico / non sarà molto, molto raramente un fattore di prestazione.
Foredecker

22
-1: ottimizzazione prematura da manuale. La velocità non dovrebbe certamente essere il primo criterio per decidere statico o non statico per il caso generale.
Non sono sicuro

2
D'accordo con Non sicuro, questo dovrebbe essere il tuo ultimo motivo per considerare mai statico o no.
Samuel,

5
Il punto è che la velocità è uno dei motivi più poveri che puoi avere per decidere se una funzione è statica o non statica nel 99% dei casi. Ci sono considerazioni molto più importanti quando si tratta di progettazione OO che altri post elaborano.
Non sono sicuro

2
@agnieszka: Il motivo speciale per utilizzare generalmente metodi di istanza invece di metodi statici è lo stato. Se lasci i metodi statici, in un'applicazione complessa introdurrai bug che ti faranno strappare i capelli. Pensa a modificare lo stato globale, le condizioni di gara, la sicurezza dei thread ecc.
Sandor Davidhazi,

5

Sono sorpreso che così pochi stiano menzionando l'incapsulamento qui in effetti. Un metodo di istanza avrà automaticamente accesso a tutti i campi, proprietà e metodi privati ​​(istanza). Oltre a tutti quelli protetti ereditati dalle classi base.

Quando scrivi codice dovresti scriverlo in modo da esporre il meno possibile e anche in modo da avere accesso al meno possibile.

Quindi sì, potrebbe essere importante rendere il tuo codice veloce, cosa che accadrebbe se rendessi statici i tuoi metodi, ma di solito più importante è rendere il tuo codice il più incapace di creare bug anche possibile. Un modo per ottenere ciò è che il tuo codice abbia accesso al minor numero possibile di "cose ​​private".

Questo potrebbe sembrare irrilevante a prima vista poiché l'OP sta ovviamente parlando di refactoring che non può andare storto in questo scenario e creare nuovi bug, tuttavia questo codice refactored deve essere mantenuto in futuro e modificato, il che rende il tuo codice un "attacco più grande" surface "per quanto riguarda i nuovi bug se ha accesso ai membri dell'istanza privata. Quindi in generale penso che la conclusione qui sia che "sì, principalmente i tuoi metodi dovrebbero essere statici" a meno che non ci siano altri motivi per non averli statici. E questo semplicemente perché è "un uso migliore dell'incapsulamento e dell'occultamento dei dati e crea codice 'più sicuro'" ...


4

Fare qualcosa di statico solo perché puoi non è una buona idea. I metodi statici dovrebbero essere statici a causa del loro design, non per caso.

Come ha detto Michael, modificarlo in seguito interromperà il codice che lo sta utilizzando.

Detto questo, sembra che tu stia creando una funzione di utilità privata per la classe che è, in effetti, statica per progettazione.


4

Se sei stato in grado di refactoring di alcune righe e il metodo risultante potrebbe essere statico, probabilmente è un'indicazione che le righe che hai estratto da quel metodo non appartengono affatto alla classe contenitore, e dovresti considerare di spostarle in la propria classe.


2

Personalmente non avrei altra scelta che renderlo statico. Resharper emette un avviso in questo caso e il nostro PM ha una regola "Nessun avviso dal Resharper".


1
Puoi modificare le impostazioni di ReSharper: P
Bernhard Hofmann

1
Se fosse così facile non avremmo avuto usure dal Resharper ... mai :)
Prankster

1

Dipende ma generalmente non rendo statici questi metodi. Il codice cambia continuamente e forse un giorno vorrò rendere virtuale quella funzione e sovrascriverla in una sottoclasse. O forse un giorno dovrà fare riferimento a variabili di istanza. Sarà più difficile apportare tali modifiche se ogni sito di chiamata deve essere modificato.


Sì, ma se un giorno hai bisogno di farlo, puoi sempre renderlo non statico. Oppure mi sfugge qualcosa?
Ray

1
@ Ray - Lo copro nella mia risposta. da statico a non statico è un cambiamento decisivo, quindi tutti i consumatori devono essere modificati. Non è un grosso problema per un piccolo programma, ma se si tratta di una libreria per il consumo da parte di altri, è necessario tenerne conto.
Michael

Tutti i siti di chiamata devono essere modificati da una chiamata di metodo statico a una chiamata di funzione membro.
Brian Ensink

Scusa, l'hai aggiunto dopo il mio commento. Nella mia mente stavo pensando ai metodi privati, ma questo è un punto valido per i metodi pubblici.
Ray

... o un giorno puoi buttarlo via. questi argomenti non sono abbastanza validi per rendere un metodo non statico.
agnieszka

1

Suggerisco che il modo migliore per pensarci è questo: se hai bisogno di un metodo di classe che deve essere chiamato quando nessuna istanza della classe viene istanziata o mantiene una sorta di stato globale, allora static è una buona idea. Ma in generale, ti suggerisco di preferire rendere i membri non statici.


1

Dovresti pensare ai tuoi metodi e classi:

  • Come li utilizzerai?
  • Hai bisogno di molti accessi a loro da diversi livelli del tuo codice?
  • È un metodo / classe che posso usare in quasi tutti i progetti pensabili.

Se gli ultimi due sono "sì", il tuo metodo / classe dovrebbe probabilmente essere statico.

L'esempio più utilizzato è probabilmente la Mathclasse. Tutti i principali linguaggi OO ce l'hanno e tutti i metodi sono statici. Perché devi essere in grado di usarli ovunque, in qualsiasi momento, senza creare un'istanza.

Un altro buon esempio è il Reverse()metodo in C #.
Questo è un metodo statico nella Arrayclasse. Inverte l'ordine del tuo array.

Codice:

public static void Reverse(Array array)

Non restituisce nemmeno nulla, l'array è invertito, perché tutti gli array sono istanze della classe Array.


La matematica è un cattivo esempio. Immagino sia meglio: newnumber = number.round (2) di newnumber = Math.round (number)
graffic

3
La classe Math è l'esempio perfetto di utilizzo di classi statiche. Questo è l'argomento di questo argomento, non su come preferisci arrotondare i numeri ...
KdgDev

1

Finché rendi statico il nuovo metodo privato, non è un cambiamento radicale. In effetti, FxCop include questa guida come una delle sue regole ( http://msdn.microsoft.com/en-us/library/ms245046(VS.80).aspx ), con le seguenti informazioni:

Dopo aver contrassegnato i metodi come statici, il compilatore emetterà siti di chiamata non virtuali a questi membri. L'emissione di siti di chiamata non virtuali impedirà un controllo in fase di esecuzione per ogni chiamata che garantisce che il puntatore all'oggetto corrente non sia 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.

Detto questo, il primo commento di David Kean riassume in modo più succinto le preoccupazioni dicendo che in realtà si tratta più di essere corretti che di migliorare le prestazioni:

Sebbene questa regola sia classificata come un problema di prestazioni, il miglioramento delle prestazioni di rendere statico un metodo è solo dell'1% circa. Piuttosto, è più un problema di correttezza che potrebbe indicare un incompleto o un bug nel membro a causa del suo mancato utilizzo di altri membri dell'istanza. Contrassegnare un metodo come statico ( condiviso in Visual Basic) rende chiaro la sua intenzione di non toccare lo stato dell'istanza.


1

Trasformerei sicuramente tutto ciò che posso in statico per un motivo diverso:

Le funzioni statiche, quando sono JIT, vengono chiamate senza un parametro "this". Ciò significa, ad esempio, che una funzione non statica a 3 parametri (metodo membro) viene inserita con 4 parametri nello stack.

La stessa funzione compilata come funzione statica verrebbe chiamata con 3 parametri. Questo può liberare i registri per il JIT e risparmiare spazio nello stack ...


1

Sono nel campo "Rendi statici solo metodi privati". Creare un metodo pubblico può introdurre un accoppiamento che non si desidera e può ridurre la testabilità: non è possibile bloccare un metodo statico pubblico.

Se si desidera eseguire un test unitario di un metodo che utilizza un metodo statico pubblico, si finisce per testare anche il metodo statico, che potrebbe non essere quello che si desidera.


1

I metodi intrinsecamente statici che per qualche motivo sono resi non statici sono semplicemente fastidiosi. Vale a dire:

Chiamo la mia banca e chiedo il mio saldo.
Chiedono il mio numero di conto.
Giusto. Metodo di istanza.

Chiamo la mia banca e chiedo il loro indirizzo postale.
Chiedono il mio numero di conto.
WTF? Fallire: avrebbe dovuto essere un metodo statico.


1
Cosa succede se clienti diversi sono serviti da filiali diverse? Inviare la corrispondenza all'ufficio principale della banca potrebbe farla arrivare alla filiale appropriata, alla fine, ma ciò non significa che un cliente non sarebbe meglio servito utilizzando l'indirizzo della particolare filiale che lo serve.
supercat

0

Lo guardo generalmente da una prospettiva funzionale di funzioni pure. Deve essere un metodo di istanza? In caso contrario, potresti trarre vantaggio dal forzare l'utente a passare le variabili e non alterare lo stato dell'istanza corrente. (Beh, potresti ancora alterare lo stato, ma il punto è, per impostazione predefinita, non farlo.) In genere progetto metodi di istanza come membri pubblici e faccio del mio meglio per rendere statici i membri privati. Se necessario (puoi quindi estrarli più facilmente in altre classi in seguito.


-1

In questi casi, tendo a spostare il metodo su una libreria statica o utils, quindi non mischio il concetto di "oggetto" con il concetto di "classe"

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.