C # - Perché i prefissi sui campi sono scoraggiati?

15

Ai vecchi tempi facevamo la notazione ungherese. Questo è ora considerato passé , e per la maggior parte non lo uso più, ma trovo ancora uso per il prefisso m_ per indicare i campi dei membri.

Per me, se sto leggendo il codice di qualcun altro, e vedo questo:

count = 3;

Suppongo che count sia una variabile locale a quella funzione e sto facendo qualcosa che verrà usato altrove nella funzione; se vedo questo:

m_count = 3;

Mi rendo subito conto che sto aggiornando lo stato dell'oggetto.

Le linee guida sullo stile di Microsoft dicono che è il modo sbagliato di fare le cose. Dovrei denominare i miei campi non pubblici esattamente come le variabili temporanee definite all'interno della funzione. No m_ , nemmeno un semplice trattino basso.

Sì, possiamo definire il nostro stile di codifica, ma poi devo confrontarmi con vari strumenti di analisi del codice statico, per convincerli che il nostro modo di fare le cose è OK.

Sono felice di passare allo stile Microsoft, ma mi piacerebbe sapere perché le cose sono come sono.

Perché ora è considerato negativo poter dire se una variabile è una funzione locale o un membro?

P.S. Questo è molto simile a Quali sono le migliori pratiche attuali riguardo alla parola chiave "this" di fronte al campo e ai metodi in c #? , ma sto chiedendo di m_ not this.

P.P.S. Vedi anche Perché Microsoft crea parametri, variabili locali e campi privati hanno la stessa convenzione di denominazione dei nomi?

    
posta Betty Crokker 14.06.2017 - 23:03
fonte

8 risposte

15

Quando stavano lavorando sull'API per Windows, Microsoft raccomandava l'uso della notazione ungherese, usando 'm_', così come 'i', 'sz', ecc. Al momento, ciò era utile perché l'IDE non era abbastanza robusto da mostrarti queste informazioni.

C #, d'altra parte, ha un IDE molto robusto fin dall'inizio.

Quindi hanno fatto la raccomandazione in Linee guida per la denominazione di Microsoft per C # per i campi pubblici statici o protetti:

✓ DO use PascalCasing in field names.
✓ DO name fields using a noun, noun phrase, or adjective.
X DO NOT use a prefix for field names.

Ora che puoi passarci sopra con il mouse, o premere CTRL + K + W, e ottenere tutte le informazioni sul membro, Microsoft ha stabilito che i prefissi sono di cattiva forma; sono una soluzione manuale per un problema già risolto.

I campi privati sono specificamente esclusi dalle linee guida, ma sembra che Microsoft sia giunta alla conclusione che questo è il caso anche per i campi privati che vengono inoltrati internamente, che puoi vedere se punti a Resharper su .NET 4.5 o .NET Core .

Utilizza i tuoi strumenti, non farlo manualmente.

    
risposta data 14.06.2017 - 23:14
fonte
15

C # non ha variabili globali, quindi lascia solo variabili locali e campi di classe.

E se hai così tante variabili locali che perdi traccia di se un identificatore è uno, hai sicuramente infranto una delle linee guida per gestire la complessità in maniera più grave.

Prova ad estrarre un oggetto-parametro, prova a dividere la tua funzione in più semplicissime, dovresti sicuramente ridefinire il tuo codice a meno che non ti piaccia annegare nelle minuzie e nella complessità, così come non avere riguardo per la manutenibilità.

Ora che abbiamo stabilito che lo scopo di "questo-is-a-membro" -decorazioni non è più valido poiché la funzione-ambito dovrebbe essere troppo piccola e l'ambito globale non esiste, c'è uno svantaggio per quei marcatori : Inibiscono lo spostamento degli argomenti / variabili locali ai membri o viceversa.

    
risposta data 14.06.2017 - 23:55
fonte
11

Perché gli sviluppatori evitano di prependere gli spazi dei nomi con l'uso della direttiva namespace?

System.DateTime() è molto più esplicito di DateTime() . Mi dice esattamente di cosa mi sto occupando. È solo perché siamo pigri dattilografi?

No. Siamo pigri dattilografi, ma non è questo il motivo.

Preferiamo stili di codifica che permettano di ignorare i dettagli e concentrarsi sulle astrazioni. Costringere i nomi a comunicare i dettagli della struttura è fonte di distrazione. Quando sto lavorando su un algoritmo complicato, non voglio nomi che insistano nel ricordarmi ogni piccolo dettaglio sulla cosa con cui sto lavorando. Ho solo bisogno del nome per impedirmi di confondere Timer e DateTime . Mi preoccuperò se questi sono compatibili da qualche altra parte.

È lo stesso motivo per cui non vuoi che due ragazzi del tuo team chiamino Jon. Il fatto che abbiano cognomi non è un motivo per dare loro prefissi o suffissi. Ti chiamerò Skeet. Qualche cosa in più è un dolore piatto.

    
risposta data 15.06.2017 - 00:16
fonte
6

Va notato che la guida allo stile di MS parla solo di metodi e variabili pubblici e protetti. cioè quelli che altri sviluppatori vedranno se usano la tua libreria.

L'idea è che le librerie Microsoft hanno un aspetto e un aspetto standard per gli sviluppatori che li consumano.

Sei libero di usare qualsiasi stile tu voglia sulle tue variabili private o locali.

Avendo detto che i prefissi variabili sono scoraggiati in generale per una serie di ragioni

  • Possono essere sbagliati e quindi fuorvianti
  • Se si esegue il prefisso in base al tipo di variabile, non è chiaro come si gestiscono le classi che sono state create.
  • Ci sono un certo numero di convenzioni e non sempre sono d'accordo. Quello che trovi utile per un altro dev potrebbe non essere di aiuto
  • Nel caso delle variabili membro puoi usare questo 'questo'. parola chiave per indicare l'ambito e il compilatore la applicherà.
risposta data 14.06.2017 - 23:54
fonte
5

Espandiamoci un po '.

Ci sono 3 stili di prefisso comuni, che si verificano occasionalmente nel codice c #:

  • m _
  • _
  • questo.

Tali prefissi sono comunemente usati nell'implementazione privata di una classe . La raccomandazione di Microsoft riguarda principalmente le parti esposte di una classe.

Il vantaggio di usare m_ su _ è che il prefisso può essere lo stesso nell'intera base di codice se usi c # e lingue in cui l'utilizzo di _ come prefisso non è consentito . * Il vantaggio di m_ su this. è che è più breve e che non ti dimenticherai accidentalmente del prefisso.

Il vantaggio di _ su m_ è che è più breve e che qualsiasi cosa che inizia con il prefisso è ordinata nella parte superiore è ordinata alfabeticamente da uno strumento. Il vantaggio di _ su this. è che è più breve e che non ti dimenticherai accidentalmente del prefisso.

Il vantaggio di this. su m_ e _ è che puoi usarlo in una base di codice dove _ o m_ non sono una convenzione accettata e universale. Ciò significa anche che nessuno deve conoscere la convenzione _ o m_ , che può essere vista come semplificare le cose. Come svantaggio, poiché il compilatore non si preoccupa di questo prefisso, il prefisso this. a volte manca e, in quanto tale, non è affidabile quanto un indicatore.

* Una volta che inizi ad accedere alle classi C # che usano _ da C ++ / CLI (che davvero non dovrebbe usare _ ), noterai che concordare un prefisso comune è più complesso di quanto dovrebbe essere. Decidere di non avere un prefisso si libera di quel rumore. Combina questo con la risposta del Deduplicator, che parafrasò come "il vantaggio di un prefisso è quasi trascurabile", e ci dà: "C'è un piccolo problema quando si utilizzano i prefissi e un piccolo vantaggio, quindi è una scelta valida semplicemente non li usa ".

C'è una domanda precedente sullo stackoverflow relativa a questo.

    
risposta data 15.06.2017 - 11:01
fonte
4

For me, if I'm reading through someone else's code, and I see this:

count = 3;

I assume that 'count' is a variable local to that function and I'm doing something that will be used elsewhere in the function

E avrai assolutamente ragione se stai leggendo il codice sorgente che rispetta le convenzioni di stile di C #. In tale codice:

this.count = 3;

assegna un valore a un campo.

count = 3;

assegna un valore a una variabile locale.

Pertanto, le convenzioni di stile di C # sono chiare e non ambigue. Ti costringono a non utilizzare alcun prefisso semplicemente perché non ne hai bisogno.

Per quanto riguarda il codice sorgente per il quale gli autori hanno deciso di utilizzare le loro convenzioni personali, dovresti chiedere a loro personalmente perché hanno scelto di farlo. Se non usano prefissi come underscore, anche se non usano this. , porterebbero in realtà non solo a un codice di difficile lettura, ma anche a casi in cui sarebbe necessaria una convenzione aggiuntiva:

public class Hello
{
    private string greetings;

    public Hello(string greetings)
    {
        greetings = greetings; // Wait, what is that?!
    }
}

Doesn't C# have the this keyword? Couldn't you refer to members using this, such as this.count?

Yes, but (1) it's more typing, and (2) it's easy to forget. If the field is named m_count I don't have to remember to type this.m_count

Qui, tuttavia, ti sbagli.

È più digitante quando scrivi il tuo codice nel Blocco note. Con un IDE con completamento automatico o, meglio, IntelliSense, il confronto tra this.count e m_count non è così ovvio. Nota Shift + - necessario per digitare il carattere di sottolineatura.

Come per "facile dimenticare", di nuovo, questo è rilevante solo per gli utenti del Blocco note. Non solo StyleCop e Resharper non ti faranno dimenticare di mettere this. quando necessario, ma dopo alcune ore di programmazione, mettere this. quando necessario diventa un'abitudine.

    
risposta data 14.06.2017 - 23:51
fonte
4

The "member" prefix is kind of an implementation detail. It distracts your attention from the problem domain to the technical solution domain which biases your mind when thinking of possible refactorings. – me

     

puoi spiegare ulteriormente? La tua è l'unica ragione per cui ho visto il perché non usare il prefisso e non lo capisco ... (con il quale intendo, le altre cose che le persone dicono sono le ragioni per cui non devo usarlo, che non è lo stesso del perché non dovrei) - Betty Crokker

Il mio punto è estendere le risposte di @CandiedOrange e @Ewan.

I prefissi rendono più difficile il refactoring

Man mano che il codice si evolve, le variabili e i metodi possono cambiare il loro ambito. Per esempio. puoi creare un metodo privato e successivamente scoprire che dovrebbe essere disponibile anche ad altre (nuove) classi. Simile può accadere ai parametri del metodo e alle variabili locali.

Supponiamo che tu crei un calcolatore delle tasse. In base al principio di scope lease visibility per le variabili, inizi con un metodo che accetta sia come parametro tax rate che base value come parametri:
(esempio potrebbe sembrare Java-ish ...)

class TaxCalculator{
   double Calculate(double p_TaxRateInpercent, double p_BaseValue){
     return (100+p_TaxRateInpercent)/100 * p_BaseValue;
   }
} 

Successivamente devi implementare l'operazione inversa e in base a TDD lo fai con il minimo sforzo:

class TaxCalculator{
   double Calculate(double p_TaxRateInpercent, double p_BaseValue){
     return (100+p_TaxRateInpercent)/100 * p_BaseValue;
   }
   double CalculateBase(double p_TaxRateInpercent, double p_TaxedValue){
     return p_TaxedValue/((100+p_TaxRateInpercent)/100);
   }
} 

Il prossimo TDD vuole che tu ridigiga il codice per diventare più pulito e che è quello di ridurre l'elenco dei parametri di entrambi i metodi.
(Sì, dovresti prima estrarre il calcolo raddoppiato, ma lasciami capire il mio punto .. .) La soluzione ovvia è di cambiare tax rate in una variabile membro passandola come parametro costruttore.

class TaxCalculator{
   double m_TaxRateInpercent;
   TaxCalculator(double p_TaxRateInpercent){
     m_TaxRateInpercent = p_TaxRateInpercent;
   }
   double Calculate(double p_BaseValue){
     return (100+m_TaxRateInpercent)/100 * p_BaseValue;
   }
   double CalculateBase(double p_TaxedValue){
     return p_TaxedValue/((100+m_TaxRateInpercent)/100);
   }
} 

Come puoi vedere, abbiamo dovuto modificare tutte le linee dei nostri metodi esistenti (qualsiasi riga che abbiamo usato p_TaxRateInpercent per essere esatti.

Il problema è che hai nessun supporto dal tuo IDE per eseguire il cambio di nome in tutta la classe. L'unico aiuto è search / replace che cambierà anche il costruttore o qualsiasi parte che contiene accidentalmente la stringa p_TaxRateInpercent .
L'IDE potrebbe offrire una modifica a .. . refactoring per nomi di variabili non definiti, ma questo può essere limitato allo scopo del metodo

Senza il prefisso solo le firme del metodo sarebbero cambiate. Nessuna modifica sarebbe stata necessaria.

I prefissi ingombrano la cronologia SCM quando vengono modificati

Anche SCM registra la modifica del prefisso come modifiche nella logica sebbene la logica non sia cambiata! La storia delle SCM è ingombra di questo cambiamento tecnico che nasconde ciò che è importante e aumenta il rischio di conflitti con i cambiamenti (reali logici) degli altri.

    
risposta data 15.06.2017 - 09:55
fonte
1

Uso il prefisso _ per tutte le variabili membro. Detesto "questo" prefisso perché, mentre alcuni sostengono che è il modo giusto di fare le cose - aggiunge un sacco di rumore / confusione al codice base. Un singolo trattino basso è anche una pratica comune negli esempi di Microsoft.

Quindi nel tuo esempio avrei:

int _count = 10;
    
risposta data 20.06.2017 - 20:46
fonte

Leggi altre domande sui tag