Arbeiten mit .NET: Allgemeines/ Anhang/ Namenskonventionen
Dieses Kapitel beschreibt die Regeln, nach denen ein Programmierer eigene Namen für Klassenbibliotheken, Klassen, Variablen usw. vergeben sollte (jedenfalls nach den Vorstellungen von Microsoft).
Die Beispiele sollen nur Anhaltspunkte geben. In der MSDN werden eine Reihe weiterer Situationen genannt.
Allgemeine Hinweise
[Bearbeiten]Die folgenden Informationen sind eine Kurzfassung der Richtlinien von Microsoft (siehe die Links). Selbstverständlich sind diese Richtlinien nur Empfehlungen (und sie gelten eigentlich auch nur für öffentliche Elemente). Auch wenn firmeninterne Richtlinien etwas anderes sagen, ist die Beachtung der MS-Richtlinien sinnvoll.
- Das gesamte Framework berücksichtigt diese Richtlinien (naja, nicht vollständig und nicht immer sinnvoll, aber im Prinzip).
- Code, der nach den Richtlinien erstellt ist, ist leichter verständlich: sowohl für den Ersteller, der sich nach längerer Zeit wieder mit etwas befassen muss, als auch für andere Programmierer, die Projekte nutzen oder überarbeiten.
- Dies erhöht insgesamt die Benutzerfreundlichkeit bei der Anwendung von Klassen und Klassenbibliotheken.
Wenn der Abteilungsleiter seit Jahrzehnten an die ungarische Notation gewöhnt ist, ist es natürlich schwierig, ihn von anderen Regeln zu überzeugen. Aber ein Versuch ist auf jeden Fall sinnvoll.
Deutsch oder Englisch?
[Bearbeiten]Die Richtlinien sagen nichts zu Bezeichnern in anderen Sprachen. Wahrscheinlich halten die .NET-Enwickler sowieso das Englische für die einzige in der EDV erlaubte Sprache. Welche Zeichen in Namen zulässig sind, wird von der jeweiligen Programmiersprache bestimmt; aber wie .NET akzeptieren auch diese Unicode, in der Regel auch für Variable u.a.
Auch wenn wir in Deutschland vorzugsweise Deutsch sprechen und schreiben (auch hier in Wikibooks), empfehlen wir dennoch, ausschließlich englische Begriffe zu verwenden.
In den .NET-Richtlinien heißt es u.a.:
- Es empfiehlt sich, den Namen einer abgeleiteten Klasse mit dem Namen der Basisklasse abzuschließen.
Wenn wir eine Klasse von DataTable für Kundendaten ableiten, erhalten wir also solch eine Definition:
Gleiches macht die IDE, wenn sie zu einer TextBox namens EingabeTitel einen EventHandler für das Ereignis Validate erzeugt:
Solcher denglischer Mischmasch ist viel schlimmer, als innerhalb von Quellcode (der sowieso überwiegend englische Begriffe enthält) auch englische Bezeichner zu verwenden:
public class CustomerDataTable : DataTable { ... }
private void TitleInput_Validate(object sender, EventArgs e) { ... }
Groß- und Kleinschreibung
[Bearbeiten]Es gibt drei Varianten für die Groß- und Kleinschreibung von Bezeichnern:
- Großbuchstaben werden für gängige Abkürzungen mehrteiliger Begriffe (Akronym genannt) verwendet. Beispiel:
IO - Bei Pascal-Schreibweise ("PascalCasing") wird der erste Buchstabe groß und jeder weitere Wortbeginn groß geschrieben. Beispiel:
RunningHuman - Bei Camel-Schreibweise ("camelCasing[1]") wird der erste Buchstabe klein und jeder weitere Wortbeginn groß geschrieben. Beispiel:
runningHuman
Abkürzungen für einteilige Begriffe sind nicht vorgesehen. Ausnahmen sind ID für identifier und OK; diese sind aber nach den „normalen“ Regeln in Pascal als Id und Ok sowie in Camel als id und ok zu schreiben.
Es gibt folgende Grundsätze:
- Alle öffentlichen Bezeichner erhalten die Pascal-Schreibweise.
- Alle privaten Bezeichner erhalten die Camel-Schreibweise.
- Bei allen Zusammensetzungen werden der zweite und folgende Bestandteil in Pascal-Schreibweise angefügt; es werden keine Striche (Unterstrich '_' oder Bindestrich '-' ) dazwischengesetzt. Das gilt uneingeschränkt auch dann, wenn ein Bestandteil eine Abkürzung aus drei und mehr Buchstaben ist.
- Wenn der erste Bestandteil eine Abkürzung aus zwei Buchstaben ist, wird er bei Camel-Schreibweise klein geschrieben.
Die folgende Tabelle bietet eine Übersicht:
Verwendungsbereich | Schreibweise | Einfache Begriffe | Zusammensetzungen |
---|---|---|---|
Klasse | Pascal | Program | AppDomain |
Enumerationstyp | Pascal | Rule [2] | ErrorLevel |
Enumerationswerte | Pascal | Monday [3] | FatalError |
Ereignis | Pascal | Click | ValueChanged |
Ausnahmeklasse | Pascal | Exception | WebException |
Schreibgeschütztes statisches Feld | Pascal | RedValue | |
Schnittstelle | Pascal | IDisposable | ICustomFormatter |
Methode | Pascal | Main | ToString |
Namespace | Pascal | System.Drawing | System.ComponentModel |
Parameter | Camel | current | typeName |
Eigenschaft | Pascal | Name | BackColor |
Feld | Camel | name | backColor |
lokale Variable | Camel | name | nameValue |
Zusammensetzungen mit Akronymen | |||
öffentlich | Pascal | IO Xml |
IOStream XmlSerializer OdbcCommand |
privat | Camel | io xml |
ioStream xmlDocument odbcParameter |
Allgemeine Regeln
[Bearbeiten]Die folgenden Hinweise [4] gelten für alle Bezeichner. In den späteren Abschnitten werden spezielle Hinweise gegeben.
Lesbarkeit und Klarheit gelten als oberste Gebote:
- Wählen Sie leicht lesbare Bezeichnernamen aus. Beispielsweise ist eine Eigenschaft mit dem Namen HorizontalAlignment im Englischen besser lesbar als AlignmentHorizontal.
- Ziehen Sie Lesbarkeit einer kurzen Bezeichnung vor. Der Eigenschaftenname CanScrollHorizontally ist besser als ScrollableX (ein unklarer Verweis auf die X-Achse).
- Verwenden Sie keine Unterstriche, Bindestriche oder andere nicht alphanumerischen Zeichen (darunter fallen auch Umlaute).
- Verwenden Sie nicht die ungarische Notation.
In der ungarischen Notation enthalten Bezeichner ein Präfix, um Metadaten über den Parameter, z.B. den Datentyp des Bezeichners, zu codieren. - Verwenden Sie keine Bezeichner, die Konflikte mit Schlüsselwörtern weit verbreiteter Programmiersprachen verursachen.
Im Allgemeinen sollten Sie keine Abkürzungen oder Akronyme verwenden.
- Durch diese wird die Lesbarkeit von Namen verringert. Außerdem ist es schwierig zu wissen, wann davon ausgegangen werden kann, dass ein Akronym allgemein bekannt ist.
- Verwenden Sie keine Abkürzungen oder Zusammenziehungen als Bestandteile von Bezeichnernamen.
Verwenden Sie beispielsweise OnButtonClick und nicht OnBtnClick. - Verwenden Sie Akronyme ohne allgemeine Gültigkeit nur, wenn dies unbedingt erforderlich ist.
Vermeiden Sie Namen, die auf eine bestimmte Programmiersprache hindeuten.
- Verwenden Sie als Typnamen allgemein interessante Namen statt sprachspezifischer Schlüsselwörter.
Beispielsweise ist GetLength besser als GetInt. - Verwenden Sie in den seltenen Fällen, in denen ein Bezeichner über keine inhaltliche Bedeutung außer seinem Typ verfügt, einen .NET-Typnamen und keinen sprachspezifischen Namen.
Beispielsweise sollte eine Methode, die Daten in Int16 konvertiert, mit ToInt16 und nicht mit ToShort benannt werden.
Verwenden Sie in den seltenen Fällen, in denen der Bezeichner keine inhaltliche Bedeutung hat und der Typ des Parameters irrelevant ist, einen allgemeinen Namen, z.B. value oder item, statt den Typnamen zu wiederholen.
Regelverstoß durch die IDE
[Bearbeiten]Vor allem wenn Sie ein Formular durch den Designer zusammenstellen, erhalten Sie einen gravierenden Verstoß gegen die o.g. Regel: „Wählen Sie leicht lesbare Bezeichnernamen...“ Die Felder, die Sie dort platzieren, erhalten solch aussagekräftige Namen wie textBox3, textBox4, button2, button7, label23, label24 usw. Solche Bezeichner gehören verboten – da wissen nach spätestens 14 Tagen auch Sie nicht mehr, welches Control für welchen Zweck gedacht ist.
Natürlich ist der Designer „entschuldigt“, er kann die Bedeutung der Controls nicht kennen. Verfahren Sie deshalb möglichst wie folgt:
- Stellen Sie das Formular mit dem Designer zusammen, sodass die Oberfläche und die Beschriftungen Ihren Vorstellungen entspricht.
- Ändern Sie anschließend alle Namen und vergeben Sie vernünftige Bezeichnungen, z.B. OKButton und CancelButton.
- Erst danach wird die eigentliche Funktionalität definiert, z.B. die Ereignisse.
Dies ist ein vernünftiger Kompromiss zwischen dem schnellen Arbeiten mit der IDE und dem korrekten Gebrauch von Namen.
Assemblys, Klassenbibliotheken
[Bearbeiten]Grundsätzlich enthält eine Assembly eine vollständige Klassenbibliothek oder Bestandteile davon und befindet sich in einer einzelnen DLL (Dynamic Link Library). [5]
Assemblys und DLLs sind die physische Gliederung einer Bibliothek. Demgegenüber entspricht ein Namespace der logischen Gliederung und sollte unabhängig von der Organisation der Assembly behandelt werden. Ein Namespace kann auf mehrere Assemblys aufgeteilt sein, und dies ist auch häufig der Fall.
Benennen Sie DLLs nach dem Muster <Company>.<Component>.dll <Component> enthält dabei einen oder mehrere durch Punkt getrennte Bestandteile. Beispiel für die Car-Klasse in einer Modelling-Klassenbibliothek:
Wikibooks.Modelling.Car.dll
Namespaces
[Bearbeiten]Die Namensräume sollen die logische Struktur der Klassen widerspiegeln. Benennen Sie sie nach dem folgenden Muster:
<Company>.(<Product>|<Technology>)[.<Feature>][.<Subnamespace>]
Die Bestandteile sind so zu verwenden:
- Zuerst kommt immer der Firmenname; auch für das .NET Framework gibt es nur System als allgemeine Basis und Microsoft als spezielle Grundlage.
- Danach kommt je nach Situation das Produkt oder ein bestimmter Aufgabenbereich.
- Schließlich kann der Namespace um Teilbereiche erweitert werden.
Dementsprechend benutzen wir für unsere Beispielanwendungen vorzugsweise diese Struktur:
Wikibooks.CSharp.<Anwendung> Wikibooks.VBNet.<Anwendung>
Benutzen Sie keinen „vorgegebenen“ Namespace-Namen, auch wenn Sie passende Erweiterungen schreiben. Beispielsweise sollten Sie für mathematische Methoden sowohl einen eigenen Namespace YourName.System als auch einen eigenen Typnamen MathEx (statt Math) verwenden, um innerhalb des Codes Konflikte zu vermeiden.
Klassen, Strukturen, Schnittstellen
[Bearbeiten]Für die Namen von Typen gelten die folgenden Regeln:
- Benutzen Sie Substantive, allenfalls substantivische Ausdrücke und nur notfalls adjektivische Ausdrücke.
- Verwenden Sie die Pascal-Schreibweise, also große Anfangsbuchstaben.
- Verwenden Sie kein Präfix (also kein 'C' als Kennzeichen für eine Klasse).
- Abweichend davon ist eine Schnittstelle mit 'I' zu bezeichnen, z.B. IComparable.
Für bestimmte Klassen mit besonderer Bedeutung soll dies bereits im Namen erkennbar sein.
Verschiedene Ableitungen
[Bearbeiten]Abgeleitete Klassen sollen als letzten Bestandteil (Suffix) den Namen der Basisklasse tragen. Dies gilt vor allem für die folgenden Typen:
Art eines Typen | Basisklasse | Namensteil | Beispiel |
---|---|---|---|
Ausnahmen | System.Exception | Exception | OutOfMemoryException |
Datenstrom | System.IO.Stream | Stream | MemoryStream |
Attributklassen | System.Attribute | Attribute | AttributeUsageAttribute |
Delegate für Ereignisse | System.Delegate | EventHandler | AssemblyLoadEventHandler |
andere Delegates | Callback | TimerCallback [6] | |
Argumente für Ereignisse | System.EventArgs | EventArgs | MouseEventArgs |
Beachten Sie, dass ein solches Suffix damit reserviert ist. Es darf nur dann für einen Typnamen verwendet werden, wenn dieser Typ direkt oder indirekt von dem betreffenden Basistyp abgeleitet wird.
Enumerationen
[Bearbeiten]Auch für Aufzählungstypen gelten die allgemeinen Regeln: kein Präfix, kein Suffix (auch nicht Enum oder Flags), Typname im Singular. Ergänzend sind zu beachten:
- Der Name der Enumeration darf nicht im Namen der Elemente wiederholt werden.
- Nur Namen für Enumerationen, deren Werte Bitfelder sind, stehen im Plural. Diese Aufzählungen werden als Flags-Enumerationen bezeichnet.
Ein Beispiel für falsche Bezeichnungen wäre:
Name der Enumeration: Wochentage Elemente: WochentagMontag, WochentagDienstag usw.
Ein Beispiel für richtige Bezeichnungen lautet:
Name der Enumeration: DayOfWeek im System-Namespace Elemente: Monday, Tuesday etc.
Die Wiederholung des Enum-Namens ist auch deshalb abwegig, weil ein Wert sowieso zusammen mit der Enumeration angegeben wird und der Wert niemals allein steht:
DayOfWeek.Monday
Member von Datentypen
[Bearbeiten]Wie schon eingangs erwähnt, gelten diese Regeln eigentlich nur für öffentliche und geschützte Elemente. Es bietet sich aber an, sie auch für private Elemente anzuwenden und dafür die Camel- statt der Pascal-Schreibweise zu verwenden.
Eigenschaften und Felder
[Bearbeiten]Eigenschaften bezeichnen Daten, die in den Objekten enthalten sind. Dafür sind Substantive, substantivische Ausdrücke und Adjektive sinnvoll.
Für private Felder gilt: Sofern eine Eigenschaft (vor allem über Getter und Setter) direkt mit einem privaten Feld verbunden ist, kann so verfahren werden:
- Sofern die Programmiersprache zwischen Groß- und Kleinschreibung unterscheidet (z.B. die C-Varianten), wird für die Eigenschaft die Pascal-Schreibweise eines Begriffs und für das Feld der gleiche Begriff in Camel-Schreibweise verwendet.
- Sofern die Programmiersprache Groß- und Kleinschreibung gleich behandelt, wird die Eigenschaft „normal“ in Pascal-Schreibweise bezeichnet; das Feld wird durch vorangesetztes 'm_' in Camel-Schreibweise als privates Member deklariert. (Dies ist eine der wenigen Ausnahmen mit Präfix und Unterstrich.)
Beispiele sind schon in der Car-Klasse des Einstiegsprogramms zu finden:
C# mit Paint als Eigenschaft und paint als Feld VB mit Paint als Eigenschaft und m_Paint als Feld
Darüber hinaus sind folgende Regeln zu beachten:
- Boolesche Eigenschaften sollen einen positiven Begriff bezeichnen. Notfalls kann auch ein Präfix Is, Can, Has o.ä. vorangestellt werden.
- Bei Verwendung von Enumerationen kann die Eigenschaft den Namen der Enumeration erhalten. In der Car-Klasse könnte die Eigenschaft Paint deshalb auch Color genannt werden.
- Doppelte Verwendung eines Begriffs als Eigenschaft und in einer Get-Methode ist nicht zulässig. Beispiel: GetNumber als Methode und Number als Eigenschaft.
Öffentliche Felder – ebenso geschützte Felder – sind nur als statische Felder, aber keinesfalls als Instanzfelder vorgesehen. Für sie gelten die gleichen Regeln wie für Eigenschaften.
Methoden
[Bearbeiten]Diese behandeln Aktionen. Deshalb sind Verben oder verbale Ausdrücke als Bezeichner zu verwenden.
Als Bezeichnung ist eine Beschreibung dafür zu wählen, was die Methode macht, aber nicht dafür, wie dies erledigt wird. Die .NET-Entwickler erklären das so: „Verwenden Sie also keine Implementierungsdetails als Methodenname.“ Zur größeren Klarheit sind durchaus mehrteilige Begriffe geeignet.
Ereignisse
[Bearbeiten]Auch diese befassen sich mit Aktionen. Deshalb sind ebenfalls Verben oder verbale Ausdrücke als Bezeichner zu verwenden.
Sofern die Ereignisse sich mit Vorher und Nachher befassen, sollen die Ereignisse durch die Gegenwarts- und Vergangenheitsform bezeichnet werden. Präfix oder Suffix wie Before und After sind zu vermeiden.
- Beispiel: Bei Formularen wird vor dem Schließen eines Fensters das FormClosing-Ereignis und danach das FormClosed-Ereignis ausgelöst.
- Im Widerspruch dazu arbeitet das TreeView-Control u.a. mit BeforeCollapse und AfterCollapse. Nun ja...
Delegates, die Ereignisse behandeln sollen, sollen das Suffix EventHandler erhalten (wie in der o.g. Tabelle erwähnt). Dafür sind außerdem die folgenden Regeln zu beachten:
- Es ist immer ein erster Parameter sender vom Typ Object vorzusehen.
- Es ist immer ein zweiter Parameter e vom Typ EventArgs vorzusehen.
- Weitere Parameter sind nicht vorgesehen.
- Der zweite Parameter kann auch eine Ableitung von EventArgs sein; diese Klasse trägt dann das Suffix EventArgs (siehe in der o.g. Tabelle).
Mit Ableitungen von EventArgs wird immer dann gearbeitet, wenn weitere Informationen ausgewertet werden können, beispielsweise KeyDownEventArgs, MouseEventArgs, CancelEventArgs.
Parameter von Methoden
[Bearbeiten]Die Namen der Parameter geben dem Programmierer, der eine Methode aufrufen und ggf. eine passende Methode auswählen soll, wichtige Hinweise zur Verwendung der Methode. Ein guter Parametername hilft deshalb ungemein bei der Benutzerfreundlichkeit einer Klassenbibliothek und soll angeben, auf welche Daten er sich auswirkt oder zu welcher Aufgabe er gehört.
Parameter werden in Camel-Schreibweise angegeben, weil sie lokal (innerhalb der Methode) verwendet werden.
Benutzen Sie einen Namen, der die Verwendung und Bedeutung des Parameters beschreibt. Der Typ des Parameters gehört nicht in den Namen, weil er sowieso angegeben wird. In den meisten Fällen sollten der Typ und der beschreibende Name eines Parameters ausreichen, um seine Verwendung zu verdeutlichen, sodass sich eine erweiterte Dokumentation erübrigt.
Lokalisierbare Ressourcen
[Bearbeiten][7] Dies bezieht sich auf Programmteile, die an bestimmte Ländereinstellungen angepasst werden müssen, beispielsweise Fehlermeldungen und Menütexte.
Für die Ressourcenschlüssel gelten die folgenden Regeln.
- Verwenden Sie die Pascal-Schreibweise.
- Geben Sie beschreibende Bezeichner statt kurzer Bezeichner an. Prägnante Namen sind vorzuziehen, aber die Lesbarkeit ist zu beachten.
- Verwenden Sie keine speziellen Schlüsselwörter aus einer Programmiersprache.
- Verwenden Sie nur alphanumerische Zeichen und Unterstriche.
- Verwenden Sie einen Punkt für die Gliederung in einer übersichtlichen Hierarchie. Beispiel: Menus.FileMenu.Close.Text
- Für Meldungen bei Exceptions muss der Ressourcenbezeichner aus dem Namen des Ausnahmetyps und einem kurzen Bezeichner für die Ausnahme bestehen. Beispiel: ArgumentException.BadEnumValue
Siehe auch
[Bearbeiten]Diese Richtlinien werden immer wieder einmal überarbeitet (letzte Änderung: November 2007), gelten aber einheitlich für alle .NET-Versionen.
- ↑ Kamel-Schreibweise genannt, da die angehängten Wörter aussehen wie Kamelbuckel.
- ↑ Eine Enumeration im System.Data-Namespace.
- ↑ Ein Wert der System.DayOfWeek-Enumeration.
- ↑ Es handelt sich in diesem Abschnitt weitgehend um gekürzte Zitate aus der MSDN, siehe Link unter „Siehe auch“.
- ↑ Eine Assembly kann auch auf mehrere DLLs aufgeteilt sein, doch kommt dies sehr selten vor und wird in den .NET-Richtlinien nicht berücksichtigt.
- ↑ Ein Delegate im System.Threading-Namespace.
- ↑ Es handelt sich in diesem Abschnitt weitgehend um Zitate aus der MSDN, siehe Link unter „Siehe auch“.