Sta usando i nomi dei parametri che differiscono dai nomi dei tipi solo dal rivestimento considerato una cattiva pratica in C #?

43

Vedo domande simili a questo riguardo ai nomi dei parametri che corrispondono alle proprietà sulla classe, ma non riesco a trovare nulla riguardo l'utilizzo di un nome parametro che è uguale al nome del tipo di parametro ad eccezione dell'involucro in C #. Non sembra essere una violazione che riesco a trovare, ma è considerata una cattiva pratica? Ad esempio, ho il seguente metodo

public Range PadRange(Range range) {}

Questo metodo prende un intervallo e restituisce un nuovo intervallo a cui è stato applicato un riempimento. Quindi, dato il contesto generico, non riesco a pensare ad un nome più descrittivo per il parametro. Tuttavia, mi viene in mente un consiglio che ho ricevuto leggendo il Code Complete su "distanza psicologica". Dice

Psychological distance can be defined as the ease in which two items can be differentiated...As you debug, be ready for the problems caused by insufficient psychological distance between similar variable names and between similar routine names. As you construct code, choose names with large differences so that you can avoid the problem.

La mia firma del metodo ha un sacco di "Range" in corso, quindi sembra che potrebbe essere un problema per quanto riguarda questa distanza psicologica. Ora, vedo molti sviluppatori fare il seguente

public Range PadRange(Range myRange) {}

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

Vedo anche il seguente

public Range PadRange(Range rangeToPad) {}

Mi piace meglio del prefisso "mio", ma non mi interessa per niente in generale. Mi sembra eccessivamente verboso e si legge goffamente come un nome variabile. Per me, è inteso che l'intervallo sarà riempito a causa del nome del metodo.

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

    
posta Jason Tyler 19.04.2018 - 17:41
fonte

7 risposte

100

Non pensarci troppo, Range range va bene. Uso questo tipo di denominazione da più di 15 anni in C #, e probabilmente molto più a lungo in C ++, e non ho mai avuto alcun vero svantaggio, al contrario.

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

    
risposta data 19.04.2018 - 17:45
fonte
17

Lo faccio sempre, mi sta dando un gran bel senso. Se si tratta di un argomento passato a un costruttore che deve essere assegnato a un membro, anche il mio membro sarà denominato intervallo e l'assegnazione sarà

this.range = range;

E di solito avrò una proprietà chiamata Range.

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

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

Nota a lato di StyleCop

Polemica garantita!

A coloro che si oppongono all'uso di "questo". Ho visto _, m, m_ e proprio niente. Il linguaggio stesso ci offre un modo universalmente riconoscibile, chiaro e inequivocabile, per indicare che abbiamo a che fare con un membro della classe. Perché mai vorresti fare a modo tuo che mutila nomi già perfetti?

L'unica ragione per cui posso pensare che è un'abitudine ereditata dall'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 mio mignolo quando lo scrivo!". Come se il tempo di battitura avesse un significato nel tempo di sviluppo totale.

Riconosco che qualsiasi stile diverso da quello a cui sei abituato solleverà qualche opposizione. Ma usando questo costantemente è difficile discutere. Ecco come funziona per me: prima di spingere un nuovo file di codice, eseguo StyleCop e troverà un numero di membri privi di "questo" qualificatore. Ho messo "questo". negli appunti, gestito dai membri e inserito. Nessuno sforzo.

StyleCop fa molto più di questo (haha). Ci sono così tanti modi in cui uno sviluppatore può (solo considerando la formattazione del codice) frustrare il lavoro di manutenzione del suo successore. StyleCop impedisce la maggior parte di loro. È inestimabile.

Se sei nuovo: in genere ti fa lamentare per una settimana o due e poi ti piacerà.

    
risposta data 19.04.2018 - 21:17
fonte
9

La mia auto-guida su come nominare metodi, parametri e variabili è piuttosto semplice:

  1. Se il nome contiene il tipo che viene passato o restituito, stai sbagliando.
  2. Assegna un nome alle cose per cui sono destinate, non per quello che sono.
  3. Ricorda sempre che il codice viene letto più di quanto non sia stato scritto.

Quindi la firma del metodo ottimale, a mio parere, sarebbe:

Range Pad(Range toPad)

Ridurre il nome del metodo è autoesplicativo.

Il nome parametro toPad dice immediatamente al lettore che probabilmente quel parametro verrà modificato sul posto dopo essere stato riempito, quindi restituito. Al contrario, non è possibile formulare ipotesi su una variabile denominata range .

Inoltre, nel corpo reale del metodo, qualsiasi altra variabile Range introdotta dovrebbe (dovrebbe) essere denominata dal loro intento, quindi potresti avere padded e unpadded ... toPad conforme a quelle convenzioni di denominazione, ma range si sporge e non si gelifica.

    
risposta data 20.04.2018 - 08:22
fonte
3

Per la denominazione di elementi di 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 dà un comportamento diverso da quello che ti aspetti, per ragioni che sono sottili. E dal momento che è dovuto a un errore di battitura, di solito è molto difficile vedere quando stai ispezionando il codice. Se un errore di battitura interrompe la compilazione del codice, il compilatore contrassegna la riga che causa il problema e puoi facilmente trovarlo e correggerlo.

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

Dovresti preoccuparti se esistessero due variabili, metodi, funzioni o proprietà nello scope corrente denominate range e Range . In tal caso, il compilatore probabilmente lo lascerà passare, e si otterrà un comportamento imprevisto in fase di esecuzione. Si noti che questo è due di qualsiasi di quei tipi di elementi di codice, non solo "due variabili" o "due funzioni" - tutti questi possono essere implicitamente espressi l'uno con l'altro, con conseguente carneficina quando viene eseguito. Potresti ricevere degli avvertimenti, ma non puoi garantire nulla di più. Hai problemi simili se hai dichiarato due tipi chiamati range e Range .

Nota che lo stesso vale per lo stile Notazione ungherese , dove i nomi sono preceduti da uno o più caratteri per dire qualcosa di più su qualunque cosa sia. Se hai una variabile chiamata Range e un puntatore ad essa chiamato PRange , è facile perdere per sbaglio il P , ad esempio. C # dovrebbe prendere questo, ma C e C ++ ti darà solo un avvertimento al massimo. O, più preoccupante, supponiamo di avere una versione doppia chiamata DRange e di ridurla a una versione float chiamata FRange . Usa il float per errore (il che è facile dato che i tasti sono adiacenti su una tastiera) e il tuo codice tipo di funziona, ma cadrà in modi strani e imprevedibili quando il processo si esaurirà di 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 dei novizi lamentarsi di nomi di variabili più lunghi che richiedono più tempo per la codifica. Sono sempre solo i novizi a lamentarsi di questo. I codificatori seri sanno che ciò che realmente richiede tempo è capire bug oscuri - e la cattiva scelta del naming è un modo classico per abbandonarti in quel particolare buco.

    
risposta data 20.04.2018 - 12:51
fonte
1

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

Questo dipende in gran parte dal contesto. Se si tratta di un file di 30 righe, le mie istruzioni non entrano realmente in gioco.

    
risposta data 19.04.2018 - 23:53
fonte
1

Penso che sia possibile utilizzare Range range ora per un motivo: 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 considerevole "distanza logica" da non confondere facilmente.

Se questo non fosse il caso, prenderei in considerazione un nome diverso o tentando di abilitare un plugin / estensione che possa fare questa evidenziazione della sintassi.

    
risposta data 20.04.2018 - 01:04
fonte
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 che sono fuorvianti e specifici. Come

public String removeNonDigits(String phoneNumber)

Il nome della funzione suona molto generico, come questo 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 ... che cosa?

Quindi, sicuro di dire Range range, potresti dire Range rangeToPad. Ma quali informazioni aggiunge? Ovviamente è l'intervallo da tenere. Cos'altro sarebbe?

L'aggiunta di un prefisso arbitrario, "mio" o "m_" o qualsiasi altra cosa, trasmette zero informazioni aggiuntive al lettore. Quando ho usato le lingue in cui il compilatore non consente a un nome di variabile di essere uguale al nome di un tipo - con o senza distinzione tra maiuscole e minuscole - talvolta ho messo un prefisso o un suffisso, solo per farlo compilare . Ma questo è solo per soddisfare il compilatore. Si potrebbe obiettare che anche se il compilatore è in grado di distinguere, ciò rende più facile per un lettore umano distinguere. Ma wow, in Java ho scritto affermazioni come "Cliente cliente = nuovo cliente ();" un miliardo di volte e non l'ho mai trovato confuso. (L'ho sempre trovato un po 'ridondante e questo mi piace molto in VB, puoi solo dire "cliente debole come nuovo cliente" e non devi dare il nome della classe due volte.)

Dove FACCIO strongmente ai nomi generici è quando ci sono due o più istanze dello stesso tipo nella stessa funzione. Parametri SPECIALMENTE. Come:

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 falsi se non lo sono, quindi sono generici e intercambiabili.

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

    
risposta data 22.04.2018 - 01:44
fonte

Leggi altre domande sui tag