L'uso dei nomi dei parametri che differiscono dai nomi dei tipi solo per il case è considerato una cattiva pratica in C #?


43

Vedo domande simili a questa per quanto riguarda i nomi dei parametri che corrispondono alle proprietà della classe, ma non riesco a trovare nulla riguardo all'utilizzo di un nome di parametro uguale al nome del tipo di parametro tranne che per il case in C #. Non sembra essere una violazione che posso trovare, ma è considerata una cattiva pratica? Ad esempio, ho il seguente metodo

public Range PadRange(Range range) {}

Questo metodo accetta un intervallo e restituisce un nuovo intervallo a cui è stato applicato del riempimento. Quindi, dato il contesto generico, non riesco a pensare a un nome più descrittivo per il parametro. Tuttavia, mi viene in mente un suggerimento che ho preso leggendo il Codice completo sulla "distanza psicologica". Dice

La distanza psicologica può essere definita come la facilità con cui due elementi possono essere differenziati ... Mentre esegui il debug, sii pronto per i problemi causati da una distanza psicologica insufficiente tra nomi di variabili simili e tra nomi di routine simili. Mentre costruisci il codice, scegli nomi con grandi differenze in modo da poter evitare il problema.

La mia firma del metodo ha un sacco di "Range" in corso, quindi sembra che possa essere un problema rispetto a questa distanza psicologica. Ora vedo molti sviluppatori fare quanto segue

public Range PadRange(Range myRange) {}

Personalmente ho un forte disgusto per questa convenzione. L'aggiunta di un prefisso "mio" ai nomi delle variabili non fornisce alcun contesto aggiuntivo.

Vedo anche quanto segue

public Range PadRange(Range rangeToPad) {}

Mi piace meglio del prefisso "mio", ma nel complesso non mi interessa ancora. Mi sembra troppo prolisso e legge goffamente come un nome variabile. Per me, è chiaro che l'intervallo sarà riempito a causa del nome del metodo.

Quindi, con tutto ciò esposto, il mio istinto è di andare con la prima firma. Per me è pulito. Non è necessario forzare il contesto quando non è necessario. Ma sto facendo di me stesso o dei futuri sviluppatori un disservizio con questa convenzione? Sto violando una buona pratica?


35
Se non riesci a trovare un parametro più descrittivo, Range rangeva bene.
Robert Harvey,

21
In questa situazione, l'IDE colora 'Range' e 'range' in modo diverso, quindi è davvero facile vedere che uno è il tipo e uno è un nome variabile.
17 del 26

10
Sì, me lo ricordo. È nelle loro linee guida di progettazione come considerazione. "CONSIDERA dare a una proprietà lo stesso nome del suo tipo." docs.microsoft.com/en-us/dotnet/standard/design-guidelines/…
Jason Tyler,

11
Anche bene: Range r(almeno per un corpo di metodo breve) e Range toPad.
Bergi,

19
Ho sempre considerato il "mio" prefisso come qualcosa che viene fatto nel codice di esempio dove viene usato per indicare al lettore che un nome dovrebbe essere cambiato in qualcos'altro a seconda del contesto. Non è qualcosa che dovrebbe effettivamente finire in qualsiasi codice reale.
Kapex,

Risposte:


100

Non pensarci troppo, Range rangeva bene. Uso questo tipo di denominazione per più di 15 anni in C #, e probabilmente molto più a lungo in C ++, e non ho mai avuto veri e propri inconvenienti, al contrario.

Naturalmente, quando si hanno diverse variabili locali nello stesso ambito, tutte dello stesso tipo, probabilmente sarà utile investire qualche sforzo mentale per distinguerle correttamente.


6
Un'altra eccezione che aggiungerei è quando l'istanza esegue un'azione specifica su di essa. C'è un po 'di spazio per essere più descrittivo sul motivo per cui il parametro è necessario, ad esempio. Wack (Bozo bozoToBeWacked) Ancora di più se il parametro è facoltativo e descrive cosa significa l'oggetto in quello scenario / che impatto avrà. La mia regola empirica se non è ovvio senza guardare al codice cosa fa il parametro, allora ha bisogno di un nome e / o commenti migliori.
Mike,

17
Vorrei considerare Wack(Bozo bozoToBeWacked)un esempio di ridondanza nel nome della variabile che è ampiamente espressa dal metodo stesso (e quindi indesiderabile per la domanda originale). Wack(Person bozo)è semanticamente più prezioso, tuttavia, poiché implica che si prevede che solo i bozo vengano sconfitti.
Miral,

2
Nel caso menzionato nel secondo paragrafo, spesso rinominerò il parametro in qualcosa del genere initialRange. È ancora molto generico ma non ha quasi lo stesso livello di disgusto myRange.
Jaquez,

@Miral: diventa più rilevante in casi come Punch(Bozo punchingBozo, Bozo bozoToBePunched). La denominazione dettagliata è più rilevante quando si deve distinguere tra più cose (che sono descritte semanticamente praticamente con le stesse parole). Il suggerimento di OP Range rangeToPadnon è necessario nel suo esempio di metodo con un parametro, ma potrebbe essere incredibilmente necessario per un metodo che accetta diversi Rangeoggetti.
Flater,

7
@Flater Punch(Bozo source, Bozo target)farebbe il lavoro
Thomas Ayoub

17

Lo faccio sempre, mi sta dando un grande pensiero. Se si tratta di un argomento passato a un costruttore che deve essere assegnato a un membro, anche il mio membro verrebbe chiamato range e il compito sarebbe

this.range = range;

E in genere avrei una proprietà chiamata Range.

Sono tutti uguali, differiscono solo nel contesto, quindi ha senso mantenere un solo nome e dovrai ricordare un solo nome. È una cosa, le differenze sono puramente tecniche.

Dovresti essere severo con i membri pienamente qualificati con "questo". però, ma è per questo che StyleCop è.

Nota laterale StyleCop

Polemica garantita!

A coloro che sostengono l'uso di "questo": ho visto _, m, m_ e proprio niente. Il linguaggio stesso ci offre un modo perfettamente chiaro, inequivocabile universalmente riconoscibile per indicare che abbiamo a che fare con un membro della classe. Perché mai vorresti inventare la tua strada che mutila nomi già perfetti?

L'unica ragione per cui riesco a pensare che sia un'abitudine ereditaria dell'era C, quando in realtà aveva senso farlo perché non c'era altro modo.

"Sono più personaggi!" Sul serio? "Il tempo di compilazione salirà alle stelle!" Sul serio? "Dovrò alzare il mignolo quando lo scrivo!". Come se il tempo di digitazione avesse un significato nel tempo di sviluppo totale.

Riconosco che qualsiasi stile diverso da quello a cui sei abituato solleverà una certa opposizione. Ma è sempre difficile discuterne. Ecco come funziona per me: prima di inviare un nuovo file di codice, eseguo StyleCop e troverà un numero di membri privi delle qualificazioni "this". Ho messo "questo". negli Appunti, eseguito dai membri e inserito. Nessuno sforzo.

StyleCop fa molto di più (haha). Esistono molti modi in cui uno sviluppatore può (solo considerando la formattazione del codice) vanificare il lavoro di manutenzione del suo successore. StyleCop ne impedisce la maggior parte. È inestimabile.

Se sei nuovo ad esso: in genere ti fa brontolare per una settimana o due e poi lo amerai.


19
" Dovresti essere severo con i membri pienamente qualificati con" questo ". Tuttavia, " -1. Non usare thistranne quando essenziale. È solo rumore altrimenti. Utilizzare _rangeper il campo e thisnon è mai necessario tranne nei metodi di estensione.
David Arno,

12
Concordo con @DavidArno. 'questo' è solo puro rumore. 'Range' è una proprietà, '_range' è un campo e 'range' è un parametro.
17 del 26

8
@David Se la variabile è un membro della classe, È essenziale e batte qualsiasi prefisso arbitrario per segnalare che stai guardando un membro della classe piuttosto che un argomento o una variabile locale.
Martin Maat,

6
Il mio IDE sparerebbe palle di fuoco nel secondo in cui assegnerei una variabile a se stessa.
Koekje,

21
@DavidArno Cura di spiegare perché il "rumore" di _è preferibile al rumore di this.? Direi che uno ha un significato applicato dal linguaggio (e in genere ha l'evidenziazione della sintassi) mentre l'altro no.
Clint,

9

La mia auto-guida su metodi di denominazione, parametri e variabili è piuttosto semplice:

  1. Se il nome contiene il tipo che viene passato o restituito, lo stai facendo in modo sbagliato.
  2. Dai un nome alle cose per come sono destinate, non per quello che sono.
  3. Ricorda sempre che il codice viene letto più di quanto sia scritto.

Quindi la firma del metodo ottimale, secondo me, sarebbe:

Range Pad(Range toPad)

Accorciare il nome del metodo è autoesplicativo.

Il nome del parametro toPaddice immediatamente al lettore che quel parametro verrà probabilmente modificato sul posto essendo riempito, quindi restituito. Al contrario, non è possibile formulare ipotesi su una variabile denominata range.

Inoltre, nel corpo reale del metodo, qualsiasi altra Rangevariabile introdotta dovrebbe (dovrebbe) essere nominata dal suo intento, quindi potresti avere paddede unpadded... toPadconformarsi a quelle convenzioni di denominazione, ma rangesporge e non gelifica.


3
padded/ unpaddedsuona bene per le variabili immutabili locali. Ma se c'è un toPadparametro mutabile , dopo che il padding è stato fatto il nome toPadnon si adatta più (a meno che il risultato non sia restituito immediatamente). Preferirei attenermi a Range rangequei casi.
Kapex,

@Kapep Lo definirei giusto result. Viene modificato e restituito . Il secondo è chiaro dal nome e il primo segue, poiché restituire un argomento non modificato non ha senso.
maaartinus,

Dalla firma, il Padmetodo restituisce a Range. Questo, per me, implica che quello che ho passato in saranno conservati, non modificato sul posto, e un nuovo, imbottita Rangesaranno restituiti. .
Aaron M. Eshbach,

1
Non sono sicuro di cosa pensare del tuo consiglio. Pad(toPad)sembra un po 'sbagliato IMHO. Fai comunque un buon punto di difesa del tuo punto di vista. Ricevi un +0 da me! :)
Eric Duminil,

Nella domanda afferma che "restituisce un nuovo intervallo a cui è stato applicato del padding". Sono d'accordo con la tua denominazione per quello che pensi sia lo scenario, ma per la vera domanda vorrei fare qualcosa come Range CreateRangeWithPadding (Range Range)
Richard Willis,

3

Per la denominazione degli elementi del codice (tipi, variabili, funzioni, qualsiasi cosa), la domanda chiave da porsi è

Se faccio un refuso, il compilatore lo troverà per me?

Il peggior tipo di bug basato su errori di battitura è quello in cui il codice viene compilato ed eseguito, ma offre un comportamento diverso da quello che ti aspetti, per ragioni che sono sottili. E poiché è dovuto a un refuso, di solito è molto difficile vedere quando si ispeziona il codice. Se un refuso interromperà la compilazione del codice, il compilatore indicherà la riga che causa il problema e potrai facilmente trovarlo e risolverlo.

Per la tua situazione in cui il tipo e la variabile differiscono solo per le maiuscole, questo sarà sempre il caso. (O quasi sempre - con uno sforzo sufficiente, sono sicuro che potresti farlo funzionare, ma dovresti davvero provare.) Quindi penso che tu stia bene lì.

Dove dovresti essere preoccupato sarebbe se ci fossero due variabili, metodi, funzioni o proprietà nell'ambito attuale chiamato rangee Range. In tal caso, il compilatore probabilmente lo lascerà passare e otterrai un comportamento imprevisto in fase di esecuzione. Si noti che questo è due di qualsiasi di quei tipi di elemento di codice, non solo "due variabili" o "due funzioni" - tutti questi possono essere implicitamente espressi gli uni agli altri, con la conseguente carneficina quando viene eseguito. Potresti ricevere avvisi, ma non puoi garantire altro. Hai problemi simili se avessi due tipi dichiarati chiamati rangee Range.

Lo stesso vale anche per lo stile di notazione ungherese , in cui i nomi sono preceduti da uno o più caratteri per dire qualcosa di più su qualunque cosa sia. Se hai una variabile chiamata Rangee un puntatore chiamato PRange, è facile perdere accidentalmente P, per esempio. C # dovrebbe prenderlo, ma C e C ++ ti daranno solo un avvertimento al massimo. O più preoccupante, supponiamo di avere una doppia versione chiamata DRangee di sottocampionarla in una versione float chiamata FRange. Usa il float uno per caso (il che è facile poiché i tasti sono adiacenti su una tastiera) e il tuo codice funzionerà in qualche modo , ma cadrà in modi strani e imprevedibili quando il processo si esaurisce in risoluzione e underflow.

Non siamo più nei giorni in cui avevamo limiti di denominazione di 8 caratteri, o 16 caratteri, o qualunque limite arbitrario. A volte ho sentito i principianti lamentarsi di nomi di variabili più lunghi che richiedevano più tempo per la codifica. Tuttavia, solo i novizi si lamentano di questo. I programmatori seri sanno che ciò che richiede davvero tempo è capire bug oscuri - e una cattiva scelta di denominazione è un modo classico per lasciarti cadere in quel buco particolare.


Solo una nota per i lettori: per C #, le persone dovrebbero davvero evitare la notazione ungherese. Mentre era utile nei vecchi tempi quando l'evidenziazione della sintassi non era una cosa o era limitata, al giorno d'oggi non aiuta davvero.
T. Sar - Ripristina Monica il

@ T.Sar Anche ai miei tempi, l'ho odiato con passione! Come dici tu, gli IDE migliori hanno risolto i problemi ai quali erano rivolti, ma appaiono ancora così spesso. Lo vedrai comunque se hai bisogno di parlare con l'API di Windows, ad esempio, per motivi storici. Non volevo colpire totalmente gli stili preferiti delle persone se a loro piace davvero, ma volevo usarlo come gancio per mostrare che le lettere maiuscole / minuscole non sono l'unico modo per rovinare i nomi.
Graham,

Sono consapevole che non stai proponendo l'uso della notazione ungherese, ma sono anche consapevole che i giovani sviluppatori hanno un'enorme debolezza per le cose con nomi interessanti. Poter dire "Il mio codice è scritto in questo stile di codice ninja super segreto: la notazione ungherese!" può sembrare irresistibilmente bello per le menti più giovani. Ho visto troppi sviluppatori cadere in preda all'hype di belle parole ... La notazione ungherese è dolore che dà la forma del codice sorgente xX
T. Sar - Reinstate Monica

@ T.Sar Abbastanza vero. "Coloro che non ricordano il passato sono condannati a ripeterlo" e tutto il resto. : /
Graham

1
Stiamo parlando della notazione ungherese originale o di come sia stata gravemente mal interpretata da Microsoft (vicino a "gli autori della documentazione del team di Windows hanno inavvertitamente inventato quello che divenne noto come Systems Hungarian" e anche nell'intervista di Joel Spolsky di Leo Laporte sull'episodio di Triangulation 277, 12-12-2016, 04 minuti 00 secondi - 06 minuti 35 secondi )?
Peter Mortensen,

1

Un aneddoto che vorrei aggiungere, mentre Range rangequesto è sintatticamente legale, potrebbe rendere le cose più difficili da eseguire il debug o il refactoring. Cerchi quella variabile denominata "range" in un file con molte variabili di tipo Range? Potresti finire per fare più lavoro in seguito a questa scelta di denominazione.

Ciò dipende in gran parte dal contesto. Se si tratta di un file di 30 righe, le mie dichiarazioni non entrano davvero in gioco.


7
Molte persone usano strumenti che distinguono tipi e parametri o variabili, per lo sviluppo di Windows. Quello che descrivi mi ricorda i bei vecchi tempi di grep su Unix.
Frank Hileman,

1
@FrankHileman Potrebbe sorprenderti, ma Unix è ancora vivo e grep è ancora in uso (: D). Poiché grep è sensibile al maiuscolo / minuscolo, il problema menzionato non esiste. Tuttavia, anche noi, odiatori di Windows dipendenti da terminali, raramente utilizziamo grep per il codice sorgente poiché l'IDE è molto meglio nelle ricerche comuni.
maaartinus,

Penso che siamo d'accordo sul fatto che la piattaforma non sia il punto. grepè un ottimo strumento, ma non è uno strumento di refactoring. Esistono strumenti di refactoring su ogni piattaforma di sviluppo che ho usato. (OS X, Ubuntu, Windows).
Eric Wilson,

@EricWilson Un tempo, grep e sed erano gli unici strumenti di refactoring su unix.
Frank Hileman,

@FrankHileman Solo perché qualcosa viene utilizzato come strumento di refactoring non significa che sia uno. Posso refactoring nel blocco note, ma questo non lo rende più di un editor di testo.
Eric Wilson,

1

Penso che puoi usare i Range rangegiorni nostri per un motivo: l'evidenziazione della sintassi. Gli IDE moderni di solito evidenziano i nomi dei tipi e i nomi dei parametri in diversi colori . Anche un tipo e una variabile hanno una notevole "distanza logica" da non confondere facilmente.

Se così non fosse, prenderei in considerazione un nome diverso o proverei ad abilitare un plug-in / un'estensione che può eseguire l'evidenziazione della sintassi.


0

Quando una funzione è generica, è ovvio che i parametri saranno generici e quindi dovrebbero avere nomi generici.

Non è quello che stai dicendo, ma ho visto funzioni che eseguono una funzione generica con nomi di parametri fuorvianti specifici. Piace

public String removeNonDigits(String phoneNumber)

Il nome della funzione sembra molto generico, in questo modo potrebbe essere applicato a molte stringhe in molte situazioni. Ma il nome del parametro è stranamente specifico, e mi chiedo se il nome della funzione sia fuorviante, o ... cosa?

Quindi certo, invece di dire Range range, potresti dire Range rangeToPad. Ma quali informazioni aggiunge? Ovviamente è la gamma da pad. Cos'altro sarebbe?

L'aggiunta di un prefisso arbitrario, "my" o "m_" o altro, trasmette zero informazioni aggiuntive al lettore. Quando ho usato lingue in cui il compilatore non consente a un nome di variabile di essere uguale al nome di un tipo - con o senza maiuscole e minuscole - a volte ho inserito un prefisso o un suffisso, solo per farlo compilare . Ma questo è solo per soddisfare il compilatore. Si potrebbe sostenere che anche se il compilatore è in grado di distinguere, ciò rende più semplice distinguere un lettore umano. Ma wow, in Java ho scritto dichiarazioni come "Customer customer = new Customer ();" un miliardo di volte e non l'ho mai trovato confuso. (L'ho sempre trovato un po 'ridondante e mi piace piuttosto che in VB puoi semplicemente dire "dim cliente come nuovo cliente" e non devi dare il nome della classe due volte.)

Dove FACCIO oggetto fortemente di nomi generici è quando ci sono due o più istanze dello stesso tipo nella stessa funzione. Parametri PARTICOLARI. Piace:

public Range pad(Range range1, Range range2)

Qual è la differenza tra range1 e range2? Come dovrei saperlo? Se è qualcosa in cui sono veramente due valori generici e intercambiabili, okay, come

public boolean overlap(Range range1, Range range2)

Mi aspetto che restituisca true se gli intervalli si sovrappongono e false in caso contrario, quindi sono generici e intercambiabili.

Ma se sono diversi, dammi un indizio su come sono diversi! Recentemente stavo lavorando a un programma che aveva una classe "Place" per contenere dati su luoghi geografici e con variabili di questo tipo denominate "p", "place", "place2", "myPlace", ecc. Wow, quelli i nomi mi aiutano davvero a determinare quale è quale.

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.