Wird die Verwendung von Parameternamen, die sich von Typnamen nur durch Groß- und Kleinschreibung unterscheiden, in C # als schlechte Praxis angesehen?

43

Ich sehe ähnliche Fragen in Bezug auf Parameternamen, die mit den Eigenschaften der Klasse übereinstimmen, kann jedoch nichts in Bezug auf die Verwendung eines Parameternamens finden, der mit dem Namen des Parametertyps identisch ist, mit Ausnahme der Groß- und Kleinschreibung in C #. Es scheint keine Verletzung zu sein, die ich finden kann, aber wird es als schlechte Praxis angesehen? Zum Beispiel habe ich die folgende Methode

public Range PadRange(Range range) {}

Diese Methode nimmt einen Bereich und gibt einen neuen Bereich zurück, auf den eine Auffüllung angewendet wurde. Angesichts des allgemeinen Kontexts kann ich mir keinen aussagekräftigeren Namen für den Parameter vorstellen. Ich erinnere mich jedoch an einen Tipp, den ich beim Lesen von Code Complete über "psychologische Distanz" erhalten habe. Es sagt

Psychologische Distanz kann als die Leichtigkeit definiert werden, mit der zwei Elemente unterschieden werden können. Seien Sie beim Debuggen auf die Probleme vorbereitet, die durch eine unzureichende psychologische Distanz zwischen ähnlichen Variablennamen und zwischen ähnlichen Routinennamen verursacht werden. Wählen Sie beim Erstellen von Code Namen mit großen Unterschieden aus, um das Problem zu vermeiden.

Meine Methodensignatur hat eine Menge "Reichweite", daher scheint es ein Problem in Bezug auf diese psychologische Distanz zu sein. Nun sehe ich viele Entwickler, die Folgendes tun

public Range PadRange(Range myRange) {}

Ich persönlich habe eine starke Abneigung gegen diese Konvention. Das Hinzufügen eines "Mein" -Präfixes zu Variablennamen bietet keinen zusätzlichen Kontext.

Ich sehe auch folgendes

public Range PadRange(Range rangeToPad) {}

Mir gefällt das besser als das "my" -Präfix, aber insgesamt interessiert es mich immer noch nicht. Es fühlt sich für mich einfach zu wortreich an und liest sich unbeholfen als Variablenname. Mir ist klar, dass der Bereich aufgrund des Methodennamens aufgefüllt wird.

Nach alledem ist es mein Magen, mit der ersten Unterschrift zu beginnen. Für mich ist es sauber. Kontext muss nicht erzwungen werden, wenn er nicht benötigt wird. Aber mache ich mir selbst oder zukünftigen Entwicklern einen schlechten Dienst mit dieser Konvention? Verstoße ich gegen eine bewährte Methode?

Jason Tyler
quelle
35
Wenn Sie keinen aussagekräftigeren Parameter finden können, Range rangeist das in Ordnung.
Robert Harvey
21
In dieser Situation färbt die IDE 'Range' und 'range' unterschiedlich ein, so dass wirklich leicht zu erkennen ist, dass einer der Typ und einer der Variablenname ist.
17 von 26
10
Ja, ich erinnere mich daran. Es ist in ihren Gestaltungsrichtlinien als Überlegung. Msgstr "BEACHTEN SIE, dass eine Eigenschaft denselben Namen wie ihr Typ hat." docs.microsoft.com/en-us/dotnet/standard/design-guidelines/…
Jason Tyler
11
Auch gut: Range r(zumindest für einen kurzen Methodenkörper) und Range toPad.
Bergi
19
Ich habe das "my" -Präfix immer als etwas betrachtet, das in Beispielcode ausgeführt wird, wo es verwendet wird, um dem Leser anzuzeigen, dass ein Name je nach Kontext in etwas anderes geändert werden sollte. Es ist nicht etwas, das eigentlich in einem echten Code enden sollte.
Kapex

Antworten:

100

Denken Sie nicht darüber nach, Range rangeist in Ordnung. Ich benutze eine solche Art der Benennung seit mehr als 15 Jahren in C # und wahrscheinlich auch länger in C ++ und habe nie echte Nachteile davon erfahren, ganz im Gegenteil.

Wenn Sie verschiedene lokale Variablen desselben Typs im selben Bereich haben, ist es wahrscheinlich hilfreich, einige mentale Anstrengungen zu unternehmen, um sie richtig zu unterscheiden.

Doc Brown
quelle
6
Eine weitere Ausnahme, die ich hinzufügen möchte, ist, wenn für die Instanz eine bestimmte Aktion ausgeführt wird. Es gibt ein wenig Raum, um genauer zu beschreiben, warum der Parameter zum Beispiel benötigt wird. Wack (Bozo bozoToBeWacked) Dies gilt umso mehr, wenn der Parameter optional ist und beschreibt, was das Objekt in diesem Szenario bedeutet bzw. welche Auswirkungen es hat. Meine Faustregel: Wenn es nicht offensichtlich ist, ohne auf den Code zu achten, was der Parameter bewirkt, muss er besser benannt und / oder kommentiert werden.
Mike
17
Ich würde Wack(Bozo bozoToBeWacked)als Beispiel eine Redundanz im Variablennamen betrachten, die von der Methode selbst reichlich ausgedrückt wird (und daher für die ursprüngliche Frage unerwünscht ist). Wack(Person bozo)ist jedoch semantisch wertvoller, da damit gerechnet wird, dass nur Bozos gefälscht werden.
Miral
2
In dem Fall, den Sie im zweiten Absatz erwähnen, werde ich den Parameter oft in so etwas wie umbenennen initialRange. Es ist immer noch sehr allgemein gehalten, hat aber nicht annähernd die gleiche Abneigung wie myRange.
Jaquez
@Miral: Es wird relevanter in Fällen wie Punch(Bozo punchingBozo, Bozo bozoToBePunched). Eine detaillierte Benennung ist relevanter, wenn Sie zwischen mehreren Dingen unterscheiden müssen (die semantisch mit so ziemlich denselben Worten beschrieben werden). Der Vorschlag von OP Range rangeToPadist in seinem Beispiel für eine Ein-Parameter-Methode nicht erforderlich, kann aber für eine Methode, die mehrere RangeObjekte aufnimmt, unglaublich notwendig sein .
Flater
7
@ Flater Punch(Bozo source, Bozo target)würde den Job machen
Thomas Ayoub
17

Ich mache das die ganze Zeit, es gibt mir ein großes Stück Verstand. Wenn es sich um ein Argument handelt, das an einen Konstruktor übergeben wird, der einem Member zugewiesen werden muss, erhält mein Member ebenfalls den Namen range, und die Zuweisung erfolgt

this.range = range;

Und ich würde in der Regel eine Eigenschaft namens Range haben.

Sie sind alle gleich und unterscheiden sich nur im Kontext. Daher ist es sinnvoll, einen einzelnen Namen beizubehalten, und Sie müssen sich nur einen Namen merken. Es ist eine Sache, die Unterschiede sind rein technisch.

Sie sollten streng mit voll qualifizierten Mitgliedern mit "this" sein. aber dafür ist StyleCop da.

StyleCop Randnotiz

Kontroverse garantiert!

Für diejenigen, die sich gegen die Verwendung von "dies" aussprechen: Ich habe _, m, m_ und einfach nichts gesehen. Die Sprache selbst bietet uns eine vollkommen klare, eindeutige und allgemein erkennbare Möglichkeit, anzuzeigen, dass es sich um ein Klassenmitglied handelt. Warum um alles in der Welt wollen Sie Ihren eigenen Weg finden, der bereits perfekte Namen verstümmelt?

Der einzige Grund, warum ich daran denken kann, ist, dass es eine alte Angewohnheit aus der C-Ära ist, als es tatsächlich Sinn machte, dies zu tun, weil es keinen anderen Weg gab.

"Es sind mehr Charaktere!" Ernsthaft? "Die Kompilierungszeit wird in die Höhe schnellen!" Ernsthaft? "Ich muss meinen kleinen Finger beim Tippen heben!" Als ob die Eingabezeit für die gesamte Entwicklungszeit von Bedeutung wäre.

Ich erkenne, dass jeder andere Stil als der, an den Sie gewöhnt sind, Widerstände hervorrufen wird. Aber es ist schwer, konsequent damit umzugehen. So funktioniert es für mich: Bevor ich eine neue Codedatei pushe, starte ich StyleCop und es werden einige Mitglieder gefunden, denen "diese" Qualifikationen fehlen. Ich habe "das" gesagt. Führen Sie in der Zwischenablage die Elemente aus und fügen Sie sie ein. Überhaupt keine Anstrengung.

StyleCop kann noch viel mehr (haha). Es gibt so viele Möglichkeiten, wie ein Entwickler (nur unter Berücksichtigung der Code-Formatierung) die Wartungsarbeiten seines Nachfolgers vereiteln kann. StyleCop verhindert die meisten von ihnen. Es ist von unschätzbarem Wert.

Wenn Sie neu darin sind: In der Regel schimpfen Sie ein oder zwei Wochen lang, und dann werden Sie es lieben.

Martin Maat
quelle
19
Msgstr " Sie sollten streng mit voll qualifizierten Mitgliedern sein, wenn" dies ", " -1 ". Verwenden Sie es thisnur, wenn es erforderlich ist. Sonst ist es nur Lärm. Verwendung _rangefür das Feld und thiswird nur bei Erweiterungsmethoden benötigt.
David Arno
12
Ich stimme mit @DavidArno überein. "Das" ist nur pures Rauschen. 'Range' ist eine Eigenschaft, '_range' ist ein Feld und 'range' ist ein Parameter.
17 von 26
8
@David Wenn die Variable ein Klassenmitglied ist, ist sie von wesentlicher Bedeutung und übertrifft jedes beliebige Präfix, um anzuzeigen, dass Sie ein Klassenmitglied und nicht ein Argument oder eine lokale Variable betrachten.
Martin Maat
6
Meine IDE würde in dem Moment Feuerbälle abschießen, in dem ich sich selbst eine Variable zuweisen würde.
Koekje
21
@DavidArno Möchtest du erklären, warum das "Rauschen" _gegenüber dem Rauschen von vorzuziehen ist this.? Ich würde argumentieren, dass eine Bedeutung durch die Sprache erzwungen wird (und normalerweise Syntaxhervorhebungen aufweist), während die andere dies nicht tut.
Clint
9

Meine Selbstanleitung zu Benennungsmethoden, Parametern und Variablen ist ziemlich einfach:

  1. Wenn der Name den Typ enthält, der übergeben oder zurückgegeben wird, machen Sie es falsch.
  2. Nennen Sie die Dinge nach dem, wofür sie bestimmt sind, nicht nach dem, was sie sind.
  3. Denken Sie immer daran, dass Code mehr gelesen als geschrieben wird.

Somit wäre die optimale Methodensignatur meiner Meinung nach:

Range Pad(Range toPad)

Das Kürzen des Methodennamens ist selbsterklärend.

Der Parametername toPadteilt dem Leser sofort mit, dass dieser Parameter wahrscheinlich direkt geändert wird, indem er aufgefüllt und dann zurückgegeben wird. Im Gegensatz dazu können keine Annahmen über eine Variable namens getroffen werden range.

Darüber hinaus Rangewürden (sollten) alle anderen Variablen, die eingeführt werden, nach ihrer Intention benannt, sodass Sie möglicherweise diese Namenskonventionen haben paddedund unpadded... sie toPaderfüllen, aber rangenur hervorstechen und nicht gelieren.

Ian Kemp
quelle
3
padded/ unpaddedklingt gut für lokale unveränderliche Variablen. Wenn es jedoch einen veränderlichen toPadParameter gibt, toPadpasst der Name nach dem Auffüllen nicht mehr (es sei denn, das Ergebnis wird sofort zurückgegeben). Ich würde mich Range rangein solchen Fällen lieber daran halten .
Kapex
@Kapep Ich würde es einfach nennen result. Es wird modifiziert und zurückgegeben . Letzteres geht aus dem Namen hervor und ersteres folgt, da die Rückgabe eines unveränderten Arguments keinen Sinn ergibt.
Maaartinus
Aus der Signatur gibt die PadMethode a zurück Range. Dies bedeutet für mich, dass der von mir übergebene beibehalten und nicht an Ort und Stelle geändert wird und ein neuer, gepolsterter zurückgegeben Rangewird. .
Aaron M. Eshbach
1
Ich bin mir nicht sicher, was ich von deinem Rat halten soll. Pad(toPad)fühlt sich irgendwie falsch IMHO. Sie verteidigen Ihren Standpunkt jedoch sehr gut. Du bekommst eine +0 von mir! :)
Eric Duminil
In der Frage heißt es, dass "ein neuer Bereich zurückgegeben wird, auf den eine Auffüllung angewendet wurde". Ich stimme Ihrer Benennung für das zu, was Sie für das Szenario halten, aber für die eigentliche Frage würde ich mich für so etwas wie Range CreateRangeWithPadding (Range Source) entscheiden
Richard Willis
3

Für die Benennung von Codeelementen (Typen, Variablen, Funktionen usw.) ist die Schlüsselfrage, die Sie sich stellen müssen

Wenn ich einen Tippfehler mache, findet der Compiler ihn dann für mich?

Die schlimmste Art von typobasiertem Fehler ist ein Fehler, bei dem der Code kompiliert und ausgeführt wird, der sich jedoch aus subtilen Gründen anders verhält als erwartet. Und da es sich um einen Tippfehler handelt, ist es normalerweise sehr schwer zu erkennen, wann Sie den Code überprüfen. Wenn ein Tippfehler die Codekompilierung stoppt, markiert der Compiler die Zeile, die das Problem verursacht, und Sie können es leicht finden und beheben.

In Ihrer Situation, in der sich Typ und Variable nur in der Groß- und Kleinschreibung unterscheiden, ist dies immer der Fall. (Oder fast immer - mit ausreichendem Aufwand, ich bin mir sicher, dass Sie es schaffen könnten, aber Sie müssten es wirklich versuchen.) Also denke ich, dass es Ihnen gut geht.

Wenn es zwei Variablen, Methoden, Funktionen oder Eigenschaften im aktuellen Gültigkeitsbereich gibt, die als rangeund bezeichnet werden, wären Sie besorgt Range. In diesem Fall wird der Compiler wahrscheinlich wird lassen Sie es durch, und Sie werden unerwartetes Verhalten zur Laufzeit erhalten. Beachten Sie, dass das ist , zwei von jedem dieser Arten von Code - Elemente, nicht nur „zwei Variablen“ oder „zwei Funktionen“ - alle diese können implizit miteinander gegossen wird, mit resultierendem Blutbad , wenn es läuft. Möglicherweise erhalten Sie Warnungen, aber Sie können nicht mehr als das garantieren. Sie haben ähnliche Probleme, wenn Sie zwei Typen als aufgerufen rangeund deklariert hatten Range.

Beachten Sie auch, dass dies auch für den ungarischen Notationsstil gilt , bei dem den Namen ein oder mehrere Zeichen vorangestellt werden, um etwas mehr darüber zu sagen, was auch immer es ist. Wenn eine Variable aufgerufen wird Rangeund ein Zeiger darauf aufgerufen wird PRange, kann dies beispielsweise leicht versehentlich übersehen werden P. C # sollte dies auffangen, aber C und C ++ geben Ihnen höchstens eine Warnung. Angenommen, Sie haben eine Double-Version mit dem Namen " DRangeFloat ", und Sie haben eine Downsampling-Version mit dem Namen "Float" FRange. Verwenden Sie den Schwimmer ein durch einen Unfall (die einfach ist , da die Tasten auf einer Tastatur benachbart sind) und Ihr Code Art von Arbeit, aber es wird in seltsame und unvorhersehbare Weise umfallen , wenn der Prozess der Auflösung abläuft und Unterschreitungen.

Wir sind nicht mehr in den Tagen, in denen wir Namensbeschränkungen von 8 Zeichen oder 16 Zeichen oder eine beliebige Beschränkung hatten. Ich habe manchmal gehört, wie Anfänger sich über längere Variablennamen beschwerten, was dazu führte, dass die Codierung länger dauerte. Es sind jedoch immer nur Anfänger, die sich darüber beschweren. Seriöse Programmierer wissen, dass es wirklich Zeit braucht, obskure Fehler zu finden - und eine falsche Namenswahl ist ein klassischer Weg, um sich in diese bestimmte Lücke fallen zu lassen.

Graham
quelle
Nur eine Anmerkung für die Leser - für C # sollten die Leute die ungarische Notation wirklich meiden. Während es in früheren Zeiten nützlich war, als das Hervorheben der Syntax keine Sache war oder eingeschränkt war, hilft es heutzutage wirklich nicht mehr.
T. Sar - Reinstate Monica
@T.Sar Schon damals habe ich es mit Leidenschaft gehasst! Wie Sie sagen, haben bessere IDEs die Probleme, auf die sie abzielten, gelöst, aber es kommt immer wieder vor. Sie sehen es immer noch, wenn Sie beispielsweise aus historischen Gründen mit der Windows-API sprechen müssen. Ich wollte die bevorzugten Stile der Leute nicht total verprügeln, wenn sie es wirklich mögen, aber ich wollte es als Haken verwenden, um zu zeigen, dass Groß- / Kleinschreibung nicht die einzige Möglichkeit ist, die Benennung zu vermasseln.
Graham
Mir ist bewusst, dass Sie nicht die Verwendung der ungarischen Notation vorschlagen, aber mir ist auch bewusst, dass junge Entwickler eine enorme Schwäche für Dinge mit coolen Namen haben. In der Lage zu sein zu sagen "Mein Code ist in diesem super geheimen Ninja-Codierungsstil geschrieben - der ungarischen Notation!" mag für die jüngeren Köpfe unwiderstehlich cool klingen. Ich habe zu viele Entwickler gesehen, die dem Hype cooler Wörter zum Opfer gefallen sind ... Ungarische Notation ist Schmerz. Gib die Form des Quellcodes xX
T. Sar - Reinstate Monica
@T.Sar Richtig. "Wer sich nicht an die Vergangenheit erinnert, ist dazu verdammt, sie zu wiederholen" und das alles. : /
Graham
1
Sprechen wir über die ursprüngliche ungarische Notation oder wie es grob von Microsoft falsch interpretiert wurde (in der Nähe von „die Autoren der Dokumentation im Windows - Team versehentlich erfunden , was später als Systeme ungarischen bekannt sein“ und auch in Interview von Joel Spolsky von Leo Laporte auf Triangulation Folge 277, 2016-12-12, 04 Minuten 00 Sekunden - 06 Minuten 35 Sekunden )?
Peter Mortensen
1

Eine Anekdote, die ich hinzufügen möchte: Range rangeDies ist zwar syntaktisch zulässig, könnte jedoch das Debuggen oder Umgestalten schwieriger machen. Suchen Sie nach dieser einen Variablen mit dem Namen "range" in einer Datei mit vielen Variablen vom Typ Range? Aufgrund dieser Benennungsoption können Sie später möglicherweise mehr Arbeit erledigen.

Dies ist jedoch weitgehend kontextabhängig. Wenn es sich um eine 30-zeilige Datei handelt, kommen meine Aussagen nicht wirklich ins Spiel.

Jacob M.
quelle
7
Die meisten Benutzer verwenden für die Windows-Entwicklung Tools, die zwischen Typen und Parametern oder Variablen unterscheiden. Was Sie beschreiben, erinnert mich an die guten alten grep-Tage unter Unix.
Frank Hileman
1
@FrankHileman Es mag Sie überraschen, aber Unix ist noch am Leben und grep wird noch verwendet (: D). Da grep standardmäßig zwischen Groß- und Kleinschreibung unterscheidet, existiert das erwähnte Problem einfach nicht. Allerdings verwenden selbst wir terminalabhängigen Windows-Hasser selten grep für den Quellcode, da die IDE bei allgemeinen Suchvorgängen viel besser ist.
Maaartinus
Ich denke, wir sind uns einig, dass die Plattform nicht der Punkt ist. grepist ein großartiges Tool, aber kein Refactoring-Tool. Und Refactoring-Tools gibt es auf jeder Entwicklungsplattform, die ich verwendet habe. (OS X, Ubuntu, Windows).
Eric Wilson
@EricWilson Zu einer Zeit waren grep und sed die einzigen Refactoring-Tools unter Unix.
Frank Hileman
@FrankHileman Nur weil etwas als Refactoring-Tool verwendet wird, heißt das noch lange nicht, dass es eines ist. Ich kann in Notepad umgestalten, aber das macht es nicht mehr als ein Texteditor.
Eric Wilson
1

Ich denke, Sie können Range rangenowdays aus einem Grund verwenden: Syntaxhervorhebung. Moderne IDEs heben in der Regel die Typnamen und die Parameternamen in verschiedenen Farben hervor . Auch ein Typ und eine Variable haben einen beträchtlichen "logischen Abstand", der nicht leicht zu verwechseln ist.

Wäre dies nicht der Fall, würde ich einen anderen Namen in Betracht ziehen oder versuchen, ein Plugin / eine Erweiterung zu aktivieren, das / die diese Syntaxhervorhebung ausführen kann.

akaltar
quelle
0

Wenn eine Funktion generisch ist, liegt es nahe, dass die Parameter generisch sind und daher generische Namen haben sollten.

Nicht das, was Sie sagen, aber ich habe Funktionen gesehen, die eine generische Funktion ausführen, deren Parameternamen irreführend spezifisch sind. Mögen

public String removeNonDigits(String phoneNumber)

Der Funktionsname klingt sehr allgemein, so dass er in vielen Situationen auf viele Zeichenfolgen angewendet werden kann. Aber der Parametername ist seltsamerweise spezifisch, was mich fragt, ob der Funktionsname irreführend ist oder ... was?

Anstatt Range range zu sagen, können Sie Range rangeToPad sagen. Aber welche Informationen fügt dies hinzu? Natürlich ist es der zu polsternde Bereich. Was wäre es noch?

Das Hinzufügen eines beliebigen Präfixes, "my" oder "m_" oder was auch immer, übermittelt dem Leser keine zusätzlichen Informationen. Wenn ich Sprachen verwendet habe, in denen der Compiler nicht zulässt, dass ein Variablenname mit einem Typennamen übereinstimmt - mit oder ohne Berücksichtigung der Groß- / Kleinschreibung -, habe ich manchmal ein Präfix oder ein Suffix angegeben, um es zum Kompilieren zu bringen . Aber das ist nur, um den Compiler zufrieden zu stellen. Man könnte argumentieren, dass selbst wenn der Compiler unterscheiden kann, dies einem menschlichen Leser das Unterscheiden erleichtert. Aber wow, in Java habe ich Aussagen wie "Kunde Kunde = neuer Kunde ();" geschrieben. eine Milliarde Mal und ich fand es nie verwirrend. (Ich fand es immer ein bisschen überflüssig, und ich mag es, dass Sie in VB einfach "Kunden als neuen Kunden dimmen" sagen können und den Klassennamen nicht zweimal eingeben müssen.)

Ich lehne generische Namen entschieden ab, wenn zwei oder mehr Instanzen desselben Typs in derselben Funktion vorhanden sind. INSBESONDERE Parameter. Mögen:

public Range pad(Range range1, Range range2)

Was ist der Unterschied zwischen range1 und range2? Woher soll ich das wissen? Wenn es etwas ist, bei dem es sich wirklich um zwei generische und austauschbare Werte handelt, okay, wie

public boolean overlap(Range range1, Range range2)

Ich würde erwarten, dass dies true zurückgibt, wenn sich die Bereiche überlappen, und false, wenn dies nicht der Fall ist. Daher sind sie generisch und austauschbar.

Aber wenn sie anders sind, gib mir einen Hinweis, wie sie anders sind! Ich habe gerade an einem Programm gearbeitet, das eine "Place" -Klasse zum Speichern von Daten über geografische Orte und mit Variablen dieses Typs namens "p", "place", "place2", "myPlace" usw. hatte. Wow, diese Namen helfen mir wirklich zu bestimmen, welche welche ist.

Jay
quelle