Eigentlich DAS Standardthema, wenn’s um Coding Guidelines geht: Wo breche ich Zeilen um und wie rücke ich ein?
Empfehlung:
* LINQ-Ausdrücke sollten konsequent und einheitlich umgebrochen werden.
* Unterausdrücke sollten einheitlich eingerückt werden.
* Die Einrückungstiefe sollte dem Standard im restlichen Code entsprechen.
Man sollte meinen, dass sich das Thema nach jahrzehntelanger Grundsatzdiskussion und automatischer Code-Formatierung in modernen IDEs von selbst erledigt hätte. Aber weit gefehlt.
Als extremes Beispiel der Anfang des RayTracers:
Einrückungstiefen von 1, 4, 5, 7 und noch mehr Zeichen. Umbrüche in einzelnen Unterausdrücken und Funktionsaufrufen. Und der Rest der Methode wird nicht besser.
Ebenso ein typischer Vertreter:
1: public ApiExpert Get(int id)
2: {
3: return this.db.eXperts
4: .Where(x => x.Id == id)
5: .ToArray()
6: .Select(x => new ApiExpert
7: {
8: Id = x.Id,
9: IsAdmin = x.IsAdmin,
10: Name = x.Name,
11: CustomerResponse = x.CustomerStatements
12: .Select(c =>
13: new KeyValuePair<string, string>(
14: c.Id.ToString(CultureInfo.InvariantCulture),
15: c.Statement))
16: })
17: .FirstOrDefault();
18: }
Willkürliche Einrückungen. Umbrüche, die sich nicht an der Logik der Abfrage orientieren. Man hat den Eindruck, der Quelltext flüchtet zum rechten Bildschirmrand.
Die gleiche Methode wird gleich besser lesbar…
1: public ApiExpert Get(int id)
2: {
3: return this.db.eXperts
4: .Where(x => x.Id == id)
5: .ToArray()
6: .Select(x => new ApiExpert
7: {
8: Id = x.Id,
9: IsAdmin = x.IsAdmin,
10: Name = x.Name,
11: CustomerResponse = x.CustomerStatements.Select(c =>
12: new KeyValuePair<string, string>(c.Id.ToString(CultureInfo.InvariantCulture), c.Statement)
13: )
14: })
15: .FirstOrDefault();
16: }
… wenn sich die Einrückungstiefe am Standard (4 Zeichen) orientiert, und wenn man beim Unterausdruck auf Umbrüche verzichtet.
Ein weiteres Beispiel aus der Praxis:
1: IQueryable<AllocationTimeSpan> allTimeSpans = _context.AllocationSet.OfType<Allocation>().Select(a => new AllocationTimeSpan
2: {
3: From = a.AllocatedFrom,
4: To = a.AllocatedTo,
5: Status = (Status)(a.Status),
6: }).Distinct().OrderBy(ts => ts.From);
Durch die Umbrüche dominiert das Mapping der Daten anstatt der Abfragelogik. Bricht man hingegen an den einzelnen Operationen um, wird die Logik gleich deutlicher, die Kette der Aufrufe offensichtlich:
1: IQueryable<AllocationTimeSpan> allTimeSpans = _context
2: .AllocationSet
3: .OfType<Allocation>()
4: .Select(a => new AllocationTimeSpan
5: {
6: From = a.AllocatedFrom,
7: To = a.AllocatedTo,
8: Status = (Status)(a.Status),
9: AvailableMDRatio = a.AvailableMDRatio
10: })
11: .Distinct()
12: .OrderBy(ts => ts.From);
Leider unterstützt einen die Code-Formatierung im Visual Studio bei der Formatierung von LINQ-Ausdrücken nicht immer so ganz ideal. Aber wenn man sich an ein oder zwei Eigenheiten gewöhnt hat (z.B. den Lambda-Ausdruck in einem Select in der gleichen Zeile zu beginnen, statt in die nächste Zeile zu rücken), dann kann man auch damit gut lesbaren Code produzieren – wenn man das will.
Sie sehen gerade einen Platzhalterinhalt von Facebook. Um auf den eigentlichen Inhalt zuzugreifen, klicken Sie auf die Schaltfläche unten. Bitte beachten Sie, dass dabei Daten an Drittanbieter weitergegeben werden.
Mehr InformationenSie sehen gerade einen Platzhalterinhalt von Instagram. Um auf den eigentlichen Inhalt zuzugreifen, klicken Sie auf die Schaltfläche unten. Bitte beachten Sie, dass dabei Daten an Drittanbieter weitergegeben werden.
Mehr InformationenSie sehen gerade einen Platzhalterinhalt von X. Um auf den eigentlichen Inhalt zuzugreifen, klicken Sie auf die Schaltfläche unten. Bitte beachten Sie, dass dabei Daten an Drittanbieter weitergegeben werden.
Mehr Informationen