Gängige C#-Codierungskonventionen
Ein Programmierstandards sind für die Aufrechterhaltung der Codelesbarkeit sowie für Konsistenz und Zusammenarbeit innerhalb eines Entwicklungsteams unerlässlich. Code, der Branchenpraktiken und etablierten Richtlinien folgt, ist einfacher zu verstehen, zu verwalten und zu erweitern. Die meisten Projekte erzwingen eine konsistente Formatvorlage durch Codekonventionen. Die Projekte dotnet/docs
und dotnet/samples
sind da keine Ausnahme. In dieser Artikelreihe lernen Sie unsere Codierungskonventionen und die Tools kennen, die wir verwenden, um sie zu erzwingen. Sie können unsere Konventionen entsprechend den Anforderungen Ihres Teams anpassen oder ändern.
Wir haben unsere Konventionen basierend auf den folgenden Zielen gewählt:
- Korrektheit: Unsere Beispiele werden in Ihre Anwendungen kopiert und eingefügt. Wir erwarten, dass wir also Code erstellen müssen, der auch nach mehreren Bearbeitungen robust und korrekt ist.
- Lehren: Der Zweck unserer Beispiele ist es, .NET und C# zu vermitteln. Aus diesem Grund legen wir keine Einschränkungen für Sprachfeatures oder APIs fest. Stattdessen zeigen diese Beispiele, wann ein Feature eine gute Wahl ist.
- Konsistenz: Leser erwarten eine konsistente Erfahrung in unseren Inhalten. Alle Beispiele sollten demselben Stil entsprechen.
- Einführung: Wir aktualisieren unsere Beispiele aggressiv, um neue Sprachfeatures zu verwenden. Diese Praxis erhöht das Bewusstsein für neue Features und macht sie allen C#-Entwicklern vertrauter.
Wichtig
Die Richtlinien werden von Microsoft verwendet, um Beispiele und die Dokumentation zu entwickeln. Sie wurden aus dem Leitfaden .NET Runtime, C#-Codierungsstil und C#-Compiler (roslyn) übernommen. Wir haben diese Richtlinien aufgrund ihrer Einführung über mehrere Jahre der Open Source-Entwicklung ausgewählt. Diese Richtlinien helfen den Mitgliedern der Gemeinschaft, sich an den Laufzeit- und Compilerprojekten zu beteiligen. Sie sollen ein Beispiel für allgemeine C#-Konventionen sein und keine maßgebliche Liste darstellen (siehe Framework-Entwurfsrichtlinien für detaillierte Richtlinien).
Die Ziele Lehren und Einführung sind der Grund dafür, dass sich die Docs-Codierungskonvention von den Laufzeit- und Compilerkonventionen unterscheidet. Sowohl die Laufzeit als auch der Compiler verfügen über strenge Leistungsmetriken für langsamste Pfade. Bei vielen anderen Anwendungen ist das nicht der Fall. Unser Ziel Lehren erfordert, dass wir kein Konstrukt verbieten. Stattdessen zeigen Beispiele, wann Konstrukte verwendet werden sollen. Wir aktualisieren Beispiele aggressiver als die meisten Produktionsanwendungen. Unser Ziel Einführung erfordert, dass wir Code zeigen, den Sie heute schreiben sollten, auch wenn im letzten Jahr geschriebener Code keine Änderungen benötigt.
In diesem Artikel werden unsere Richtlinien erläutert. Die Richtlinien werden im Laufe der Zeit weiterentwickelt, und Sie finden Beispiele, die nicht unseren Richtlinien entsprechen. Wir freuen uns über PRs, die diese Beispiele konform machen, oder über Probleme, die uns auf Proben aufmerksam machen, die wir aktualisieren sollten. Unsere Richtlinien sind Open Source und wir freuen uns immer über PRs und Probleme. Wenn Ihr Beitrag diese Empfehlungen jedoch ändern würde, sollten Sie das Thema jedoch zunächst zur Diskussion stellen. Sie können unsere Richtlinien gerne verwenden oder sie an Ihre Bedürfnisse anpassen.
Analysetools und andere Tools
Tools können Ihrem Team dabei helfen, Ihre Konventionen zu erzwingen. Sie können die Codeanalyse aktivieren, um die gewünschten Regeln zu erzwingen. Sie können auch eine editorconfig erstellen, sodass Visual Studio Ihre Stilrichtlinien automatisch erzwingt. Als Ausgangspunkt können Sie die dotnet/docs
.editorconfig unseren Stil zu verwenden.
Diese Tools erleichtern es Ihrem Team, Ihre bevorzugten Richtlinien zu übernehmen. Visual Studio wendet die Regeln in allen .editorconfig Dateien im Geltungsbereich, um Ihren Code zu formatieren. Sie können mehrere Konfigurationen verwenden, um unternehmensweite Konventionen, Teamkonventionen und sogar projektspezifische Konventionen zu erzwingen.
Die Codeanalyse erzeugt Warnungen und Diagnosen, wenn Regelverletzungen erkannt werden. Sie konfigurieren die Regeln, die auf Ihr Projekt angewendet werden sollen. Anschließend benachrichtigt jeder CI-Build Entwickler, wenn sie gegen eine der Regeln verstoßen.
Diagnose-IDs
Sprachrichtlinien
In den folgenden Abschnitten werden die Vorgehensweisen beschrieben, denen das .NET-Dokumentationsteam folgt, um Codebeispiele zu erstellen. Im Allgemeinen werden die folgenden Praktiken befolgt:
- Verwendung moderner Sprachfeatures und C#-Versionen, falls möglich.
- Vermeiden Sie veraltete Sprachkonstrukte.
- Fangen Sie nur Ausnahmen ab, die ordnungsgemäß behandelt werden können; vermeiden Sie es, allgemeine Ausnahmen abzufangen. Zum Beispiel sollte der Beispielcode nicht die System.Exception Typ ohne Ausnahmefilter.
- Verwenden spezifischer Ausnahmetypen, um aussagekräftige Fehlermeldungen bereitzustellen.
- Verwenden von LINQ-Abfragen und -Methoden für die Sammlungsmanipulation, um die Lesbarkeit von Code zu verbessern.
- Verwenden von asynchroner Programmierung mit Async und Await für E/A-gebundene Vorgänge.
- Vorsicht bei Deadlocks und Verwenden von Task.ConfigureAwait bei Bedarf.
- Verwenden von Sprachstichwörtern für Datentypen anstelle der Laufzeittypen. Z. B.
string
anstelle von System.String oderint
anstelle von System.Int32. Diese Empfehlung umfasst die Verwendung der Typennint
undnuint
. - Verwenden von
int
anstelle von Typen ohne Vorzeichen. Die Verwendung vonint
ist in C# üblich; durch den Einsatz vonint
wird die Interaktion mit anderen Bibliotheken vereinfacht. Ausnahmen gelten für Dokumentation speziell für nicht signierte Datentypen. - Verwenden Sie
var
nur, wenn ein Leser den Typ aus dem Ausdruck ableiten kann. Leser sehen unsere Beispiele auf der Dokumentenplattform. Es gibt keine Mauszeiger- oder Tooltipps, die den Typ der Variablen anzeigen. - Schreiben Sie Code mit Klarheit und Einfachheit.
- Vermeiden Sie übermäßig komplexe und konvolutierte Codelogik.
Weitere spezifische Richtlinien folgen.
Zeichenfolgendaten
Verwenden Sie die Zeichenfolgeninterpolation, um wie im folgenden Code gezeigt kurze Zeichenfolgen zu verketten.
string displayName = $"{nameList[n].LastName}, {nameList[n].FirstName}";
Verwenden Sie ein System.Text.StringBuilder-Objekt, um Zeichenfolgen in Schleifen anzufügen, besonders bei der Arbeit mit großen Textmengen.
var phrase = "lalalalalalalalalalalalalalalalalalalalalalalalalalalalalala"; var manyPhrases = new StringBuilder(); for (var i = 0; i < 10000; i++) { manyPhrases.Append(phrase); } //Console.WriteLine("tra" + manyPhrases);
Bevorzugen Sie rohe String-Literale gegenüber Escape-Sequenzen oder verbatim-Strings.
var message = """ This is a long message that spans across multiple lines. It uses raw string literals. This means we can also include characters like \n and \t without escaping them. """;
Verwenden Sie die ausdrucksbasierte String-Interpolation anstelle der positionellen String-Interpolation.
// Execute the queries. Console.WriteLine("scoreQuery:"); foreach (var student in scoreQuery) { Console.WriteLine($"{student.Last} Score: {student.score}"); }
Konstruktoren und Initialisierung
Verwenden Sie Pascal-Großbuchstaben für primäre Konstruktorparameter bei Datensatztypen:
public record Person(string FirstName, string LastName);
Verwenden Sie CamelCase für primäre Konstruktorparameter in Klassen- und Strukturtypen.
Verwenden Sie
required
Eigenschaften anstelle von Konstruktoren, um die Initialisierung von Eigenschaftswerten zu erzwingen:public class LabelledContainer<T>(string label) { public string Label { get; } = label; public required T Contents { get; init; } }
Arrays und Sammlungen
- Verwenden Sie Auflistungsausdrücke, um alle Auflistungstypen zu initialisieren:
string[] vowels = [ "a", "e", "i", "o", "u" ];
Delegaten
- Verwenden Sie
Func<>
undAction<>
, anstatt Delegattypen zu definieren. Definieren Sie in einer Klasse die Delegatmethode.
Action<string> actionExample1 = x => Console.WriteLine($"x is: {x}");
Action<string, string> actionExample2 = (x, y) =>
Console.WriteLine($"x is: {x}, y is {y}");
Func<string, int> funcExample1 = x => Convert.ToInt32(x);
Func<int, int, int> funcExample2 = (x, y) => x + y;
- Rufen Sie die Methode mit der Signatur auf, die vom
Func<>
- oderAction<>
-Delegaten definiert wird.
actionExample1("string for x");
actionExample2("string for x", "string for y");
Console.WriteLine($"The value is {funcExample1("1")}");
Console.WriteLine($"The sum is {funcExample2(1, 2)}");
Wenn Sie Instanzen eines Delegattyps erstellen, verwenden Sie die präzise Syntax. Definieren Sie in einer Klasse den Delegattyp und eine Methode, die eine übereinstimmende Signatur besitzt.
public delegate void Del(string message); public static void DelMethod(string str) { Console.WriteLine("DelMethod argument: {0}", str); }
Erstellen Sie eine Instanz des Delegattyps, und rufen Sie sie auf. Die folgende Deklaration zeigt die komprimierte Syntax.
Del exampleDel2 = DelMethod; exampleDel2("Hey");
In der folgenden Deklaration wird die vollständige Syntax verwendet.
Del exampleDel1 = new Del(DelMethod); exampleDel1("Hey");
try-catch
- und using
-Anweisungen in der Ausnahmebehandlung
Verwenden Sie eine try-catch-Anweisung für die meisten Ausnahmebehandlungen.
static double ComputeDistance(double x1, double y1, double x2, double y2) { try { return Math.Sqrt((x1 - x2) * (x1 - x2) + (y1 - y2) * (y1 - y2)); } catch (System.ArithmeticException ex) { Console.WriteLine($"Arithmetic overflow or underflow: {ex}"); throw; } }
Vereinfachen Sie den Code mithilfe der C#-Anweisung using. Verwenden Sie bei einer try-finally-Anweisung, in der der einzige Code im
finally
-Block ein Aufruf der Dispose-Methode ist, stattdessen eineusing
-Anweisung.Im folgenden Beispiel ruft die
try-finally
-Anweisung nurDispose
imfinally
-Block auf.Font bodyStyle = new Font("Arial", 10.0f); try { byte charset = bodyStyle.GdiCharSet; } finally { bodyStyle?.Dispose(); }
Dasselbe können Sie mit einer
using
-Anweisung erreichen.using (Font arial = new Font("Arial", 10.0f)) { byte charset2 = arial.GdiCharSet; }
Verwenden Sie die neue
using
-Syntax, die keine geschweiften Klammern erfordert:using Font normalStyle = new Font("Arial", 10.0f); byte charset3 = normalStyle.GdiCharSet;
Die Operatoren &&
und ||
Verwenden Sie
&&
anstelle von&
und||
anstelle von|
, wenn Sie Vergleiche ausführen, wie im folgenden Beispiel gezeigt.Console.Write("Enter a dividend: "); int dividend = Convert.ToInt32(Console.ReadLine()); Console.Write("Enter a divisor: "); int divisor = Convert.ToInt32(Console.ReadLine()); if ((divisor != 0) && (dividend / divisor) is var result) { Console.WriteLine("Quotient: {0}", result); } else { Console.WriteLine("Attempted division by 0 ends up here."); }
Wenn der Divisor 0 ist, würde die zweite Klausel in der if
-Anweisung einen Laufzeitfehler verursachen. Wenn der erste Ausdruck „false“ ist, wird der &&-Operator kurzgeschlossen. Dies bedeutet, dass er den zweiten Ausdruck nicht auswertet. Der &-Operator würde beide auswerten, was zu einem Laufzeitfehler führt, wenn divisor
gleich 0 ist.
new
-Operator
Verwenden Sie eine der prägnanten Formen der Objektinstanziierung, wenn der Variabletyp dem Objekttyp entspricht, wie in den folgenden Deklarationen gezeigt. Dieses Formular ist ungültig, wenn es sich bei der Variablen um einen Schnittstellentyp oder eine Basisklasse des Laufzeittyps handelt.
var firstExample = new ExampleClass();
ExampleClass instance2 = new();
Die vorangehenden Deklarationen entsprechen der folgenden Deklaration.
ExampleClass secondExample = new ExampleClass();
Verwenden Sie Objektinitialisierer, um die Objekterstellung zu vereinfachen, wie im folgenden Beispiel gezeigt.
var thirdExample = new ExampleClass { Name = "Desktop", ID = 37414, Location = "Redmond", Age = 2.3 };
Im folgenden Beispiel werden dieselben Eigenschaften wie im vorangehenden Beispiel festgelegt, dabei aber keine Initialisierer verwendet.
var fourthExample = new ExampleClass(); fourthExample.Name = "Desktop"; fourthExample.ID = 37414; fourthExample.Location = "Redmond"; fourthExample.Age = 2.3;
Ereignisbehandlung
- Verwenden Sie einen Lambdaausdruck, wenn Sie einen Ereignishandler definieren, den Sie später nicht entfernen müssen:
public Form2()
{
this.Click += (s, e) =>
{
MessageBox.Show(
((MouseEventArgs)e).Location.ToString());
};
}
Der Lambdaausdruck verkürzt die folgende herkömmliche Definition.
public Form1()
{
this.Click += new EventHandler(Form1_Click);
}
void Form1_Click(object? sender, EventArgs e)
{
MessageBox.Show(((MouseEventArgs)e).Location.ToString());
}
Statische Member
Rufen Sie statische Member über diesen Klassennamen auf: ClassName.StaticMember. Durch diese Empfehlung ist der Code besser lesbar, da der statische Zugriff eindeutig ist. Qualifizieren Sie keinen statischen Member, der in einer Basisklasse mit dem Namen einer abgeleiteten Klasse definiert ist. Dieser Code lässt sich zwar kompilieren, aber die Lesbarkeit des Codes ist irreführend, und der Code könnte in Zukunft versagen, wenn Sie der abgeleiteten Klasse ein statisches Mitglied mit demselben Namen hinzufügen.
LINQ-Abfragen
Verwenden Sie aussagekräftige Namen für Abfragevariablen. Im folgenden Beispiel wird
seattleCustomers
für Kunden in Seattle verwendet.var seattleCustomers = from customer in Customers where customer.City == "Seattle" select customer.Name;
Verwenden Sie Aliase, um mithilfe der Pascal-Schreibweise sicherzustellen, dass die korrekte Großschreibung von Eigenschaftennamen anonymer Typen verwendet wird.
var localDistributors = from customer in Customers join distributor in Distributors on customer.City equals distributor.City select new { Customer = customer, Distributor = distributor };
Benennen Sie Eigenschaften um, wenn die Eigenschaftennamen im Ergebnis nicht eindeutig sind. Wenn Ihre Abfrage zum Beispiel einen Kundennamen und einen Händlernamen zurückgibt, sollten Sie diese nicht als Form von
Name
im Ergebnis, benennen Sie sie um, um zu verdeutlichenCustomerName
ist der Name eines Kunden, undDistributorName
ist der Name eines Verteilers.var localDistributors2 = from customer in Customers join distributor in Distributors on customer.City equals distributor.City select new { CustomerName = customer.Name, DistributorName = distributor.Name };
Verwenden Sie die implizierte Typisierung in der Deklaration von Abfragevariablen und Bereichsvariablen. Dieser Leitfaden zum impliziten Eingeben in LINQ-Abfragen setzt die allgemeinen Regeln für implizit typisierte lokale Variablen außer Kraft. LINQ-Abfragen verwenden häufig Projektionen, die anonyme Typen erstellen. Andere Abfrageausdrücke erstellen Ergebnisse mit geschachtelten generischen Typen. Implizite Typvariablen sind häufig besser lesbar.
var seattleCustomers = from customer in Customers where customer.City == "Seattle" select customer.Name;
Richten Sie Abfrageklauseln unter der
from
-Klausel aus, wie in den vorherigen Beispielen gezeigt.Verwenden Sie vor anderen Abfrageklauseln
where
-Klauseln, um sicherzustellen, dass nachfolgende Abfrageklauseln für den reduzierten, gefilterten Datensatz ausgeführt werden.var seattleCustomers2 = from customer in Customers where customer.City == "Seattle" orderby customer.Name select customer;
Zugriff auf innere Sammlungen mit mehreren
from
Klauseln anstelle einerjoin
Klausel. Eine Auflistung vonStudent
-Objekten kann beispielsweise jeweils eine Auflistung von Testergebnissen enthalten. Wenn die folgende Abfrage ausgeführt wird, gibt sie jede Bewertung zurück, die über 90 ist, zusammen mit dem Familiennamen des Kursteilnehmers, der die Bewertung erhalten hat.var scoreQuery = from student in students from score in student.Scores where score > 90 select new { Last = student.LastName, score };
Implizit typisierte lokale Variablen
Verwenden Sie die implizite Typisierung für lokale Variablen, wenn der Typ der Variablen auf der rechten Seite der Zuweisung offensichtlich ist.
var message = "This is clearly a string."; var currentTemperature = 27;
Verwenden Sie nicht var, wenn der Typ nicht von der rechten Seite der Zuweisung offensichtlich ist. Gehen Sie nicht davon aus, dass der Typ aus einem Methodennamen ersichtlich und somit eindeutig ist. Ein Variablentyp wird als eindeutig betrachtet, wenn er ein
new
Operator, einen expliziten Cast oder eine Zuweisung zu einem Literalwert.int numberOfIterations = Convert.ToInt32(Console.ReadLine()); int currentMaximum = ExampleClass.ResultSoFar();
Verwenden Sie keine Variablennamen, um den Typ der Variablen anzugeben. Er ist unter Umständen nicht korrekt. Verwenden Sie stattdessen den Typ, um den Typ anzugeben, und verwenden Sie den Variablennamen, um die semantischen Informationen der Variablen anzugeben. Im folgenden Beispiel sollte
string
für den Typ und etwas wieiterations
verwendet werden, um die Bedeutung der aus der Konsole gelesenen Informationen anzugeben.var inputInt = Console.ReadLine(); Console.WriteLine(inputInt);
Vermeiden Sie den Einsatz von
var
anstelle von dynamic. Verwenden Siedynamic
, wenn Sie den Laufzeit-Typrückschluss verwenden möchten. Weitere Informationen finden Sie unter Verwenden des Typs „dynamic“ (C#-Programmierhandbuch).Verwenden Sie die implizite Eingabe für die Schleifenvariable in
for
-Schleifen.Im folgenden Beispiel wird die implizite Typisierung in einer
for
-Anweisung verwendet.var phrase = "lalalalalalalalalalalalalalalalalalalalalalalalalalalalalala"; var manyPhrases = new StringBuilder(); for (var i = 0; i < 10000; i++) { manyPhrases.Append(phrase); } //Console.WriteLine("tra" + manyPhrases);
Verwenden Sie nicht die implizite Typisierung, um den Typ der Schleifenvariablen in
foreach
-Schleifen zu bestimmen. In den meisten Fällen ist der Typ der Elemente in der Sammlung nicht sofort offensichtlich. Der Name der Sammlung sollte nicht nur vom Rückschluss auf den Typ ihrer Elemente abhängen.Im folgenden Beispiel wird die explizite Typisierung in einer
foreach
-Anweisung verwendet.foreach (char ch in laugh) { if (ch == 'h') { Console.Write("H"); } else { Console.Write(ch); } } Console.WriteLine();
Verwenden Sie impliziten Typ für die Ergebnissequenzen in LINQ-Abfragen. Im Abschnitt zu LINQ wird erläutert, dass viele LINQ-Abfragen zu anonymen Typen führen, bei denen implizite Typen verwendet werden müssen. Andere Abfragen führen zu geschachtelten generischen Typen, bei denen
var
besser lesbar ist.Hinweis
Achten Sie darauf, nicht versehentlich den Typ eines Elements in der Iterable-Sammlung zu ändern. Beispielsweise ist es einfach, von System.Linq.IQueryable zu System.Collections.IEnumerable in einer
foreach
-Anweisung zu wechseln, die die Ausführung einer Abfrage ändert.
Einige unserer Beispiele erläutern den natürlichen Typ eines Ausdrucks. Diese Beispiele müssen var
verwenden, damit der Compiler den natürlichen Typ auswählt. Obwohl diese Beispiele weniger offensichtlich sind, ist die Verwendung von var
für das Beispiel erforderlich. Der Text sollte das Verhalten erläutern.
Namespace-Deklarationen mit Dateispezifikation
Die meisten Codedateien deklarieren einen einzelnen Namespace. Daher sollten in unseren Beispielen die dateibezogenen Namespace-Deklarationen verwendet werden.
namespace MySampleCode;
Platzieren der using-Anweisungen außerhalb der Namespace-Deklaration
Wenn sich eine using
-Anweisung außerhalb einer Namespace-Deklaration befindet, ist dieser importierte Namespace der vollqualifizierte Name. Der vollqualifizierte Name ist deutlicher. Wenn sich die using
-Anweisung innerhalb des Namespace befindet, kann sie entweder relativ zu diesem Namespace sein oder es kann sich um einen vollqualifizierten Namen handeln.
using Azure;
namespace CoolStuff.AwesomeFeature
{
public class Awesome
{
public void Stuff()
{
WaitUntil wait = WaitUntil.Completed;
// ...
}
}
}
Vorausgesetzt, es gibt einen Verweis (direkt oder indirekt) auf die WaitUntil-Klasse.
Nun nehmen wir eine kleine Änderung vor:
namespace CoolStuff.AwesomeFeature
{
using Azure;
public class Awesome
{
public void Stuff()
{
WaitUntil wait = WaitUntil.Completed;
// ...
}
}
}
Und kompilieren heute. Und morgen. Aber irgendwann nächste Woche schlägt der vorherige (unveränderte) Code mit zwei Fehlern fehl:
- error CS0246: The type or namespace name 'WaitUntil' could not be found (are you missing a using directive or an assembly reference?)
- error CS0103: The name 'WaitUntil' does not exist in the current context
Eine der Abhängigkeiten, die diese Klasse in einem Namespace eingeführt hat, endet dann mit .Azure
:
namespace CoolStuff.Azure
{
public class SecretsManagement
{
public string FetchFromKeyVault(string vaultId, string secretId) { return null; }
}
}
Eine using
-Direktive, die in einem Namespace platziert wurde, ist kontextbezogen und erschwert die Namensauflösung. In diesem Beispiel ist es der erste gefundene Namespace.
CoolStuff.AwesomeFeature.Azure
CoolStuff.Azure
Azure
Das Hinzufügen eines neuen Namespace, der entweder mit CoolStuff.Azure
oder CoolStuff.AwesomeFeature.Azure
übereinstimmt, wäre eine Übereinstimmung vor dem globalen Azure
-Namespace. Sie können dies beheben, indem Sie der Deklaration den global::
-Modifizierer zur using
-Deklaration hinzufügen. Es ist jedoch einfacher, using
-Deklarationen stattdessen außerhalb des Namespace zu platzieren.
namespace CoolStuff.AwesomeFeature
{
using global::Azure;
public class Awesome
{
public void Stuff()
{
WaitUntil wait = WaitUntil.Completed;
// ...
}
}
}
Stilrichtlinien
Verwenden Sie im Allgemeinen das folgende Format für Codebeispiele:
- Verwenden Sie vier Leerzeichen für den Einzug. Verwenden Sie keine Tabulatoren.
- Richten Sie den Code konsistent aus, um die Lesbarkeit zu verbessern.
- Beschränken Sie Zeilen auf 65 Zeichen, um die Lesbarkeit von Code in Dokumenten zu verbessern, insbesondere auf mobilen Bildschirmen.
- Verbessern Sie Klarheit und Benutzerfreundlichkeit, indem Sie lange Anweisungen in mehrere Zeilen aufteilen.
- Verwenden Sie die Formatvorlage „Allman“ für geschweifte Klammern: für öffnende und schließende geschweifte Klammer eine eigene neue Zeile. Geschweifte Klammern werden an der aktuellen Einzugsebene ausgerichtet.
- Zeilenumbrüche sollten bei Bedarf vor binären Operatoren auftreten.
Kommentarstil
Verwenden Sie einzeilige Kommentare (
//
) für kurze Erläuterungen.Vermeiden Sie mehrzeilige Kommentare (
/* */
) für längere Erklärungen.
Kommentare in den Codebeispielen werden nicht lokalisiert. Das bedeutet, dass im Code eingebettete Erklärungen nicht übersetzt werden. Längere, erläuternde Texte sollten in den Begleitartikel eingefügt werden, damit sie lokalisiert werden können.Zum Beschreiben von Methoden, Klassen, Feldern und allen öffentlichen Membern werden XML-Kommentare verwendet.
Fügen Sie den Kommentar in einer eigenen Zeile und nicht am Ende einer Codezeile ein.
Beginnen Sie Kommentartext mit einem Großbuchstaben.
Beenden Sie den Kommentartext mit einem Punkt.
Fügen Sie ein Leerzeichen zwischen dem Kommentartrennzeichen (
//
) und dem Kommentartext ein, wie im folgenden Beispiel gezeigt.// The following declaration creates a query. It does not run // the query.
Layoutkonventionen
Ein gutes Layout verwendet Formatierungen, um die Struktur des Codes hervorzuheben und um den Code verständlicher zu gestalten. Microsoft-Beispiele entsprechen den folgenden Konventionen:
Verwenden Sie die Code-Editor-Standardeinstellungen (Intelligenter Einzug, vierstelliger Einzug, als Leerzeichen gespeicherte Tabulatoren). Weitere Informationen finden Sie unter Optionen, Text-Editor, C#, Formatierung.
Schreiben Sie pro Zeile nur eine Anweisung.
Schreiben Sie pro Zeile nur eine Deklaration.
Wenn Fortsetzungszeilen nicht automatisch eingezogen werden, rücken Sie diese um einen Tabstopp (vier Leerzeichen) ein.
Fügen Sie zwischen Methoden- und Eigenschaftsdefinitionen mindestens eine Leerzeile ein.
Verwenden Sie Klammern, um Klauseln in einem Ausdruck zu kennzeichnen, wie im folgenden Code gezeigt.
if ((startX > endX) && (startX > previousX)) { // Take appropriate action. }
Ausnahmen sind, wenn im Beispiel die Rangfolge von Operatoren oder Ausdrücken erläutert wird.
Sicherheit
Befolgen Sie die Richtlinien in Richtlinien für das Schreiben von sicherem Code.