![]() |
AW: Delphi merkt nicht wenn ein case-Statement vollständig ist, oder?
Ich persönlich hätte auch etwas gegen einen Compilerfehler bei unvollständigem
Delphi-Quellcode:
. Es kommt schon häufiger vor, dass ich vorab per
case x of
Delphi-Quellcode:
eine Bereichsprüfung mache und dann mit einem
if x in [..] then
Delphi-Quellcode:
die verschiedenen (in diesem Bereich möglichen) Fälle auseinandernehme.
case x of
Gäbe es generell einen Fehler bei einem unvollständigen case-Statement wäre die else-Syntax ja auch überflüssig. Nichtsdestotrotz gibt es bei mir auch reichlich case-Konstrukte, bei denen im else-Zweig eine EProgrammerNotFound Exception geworfen wird. Die bereits anderswo erwähnten Unit-Tests sind dabei schon sehr hilfreich. |
AW: Delphi merkt nicht wenn ein case-Statement vollständig ist, oder?
Zitat:
|
AW: Delphi merkt nicht wenn ein case-Statement vollständig ist, oder?
Zitat:
|
AW: Delphi merkt nicht wenn ein case-Statement vollständig ist, oder?
Zitat:
Delphi-Quellcode:
zu machen?
if x in [..]
Z.B. Performance, oder so? Ich meine ein "case x of" sollte immer am performantesten sein und das zusätzliche "if x in" überflüssig machen. Ok, bei großen Strukturen wird es unlesbarer ... |
AW: Delphi merkt nicht wenn ein case-Statement vollständig ist, oder?
Das hat eigentlich ganz andere Gründe. Nehmen wir z.B. einen Enum-Typ, der positive und negative Elemente enthält. Bei positiven bzw. negativen Werten sind spezifische Code-Teile auszuführen, die teilweise vom genauen Wert unabhängig sind, während andere Teile vom exakten Wert abhängen:
Delphi-Quellcode:
type
{$SCOPEDENUMS ON} TRating = (undefined, Perfect, OK, Acceptable, NotGoodEnough, Bad, TotalShit); TRatingHelper = record helper for TRating procedure HandleIncompleteCase(Rating: TRating); end; procedure TRatingHelper.HandleIncompleteCase(Rating: TRating); begin raise EProgrammerNotFound.Create('unhandled case for TRating: ' + TRttiEnumerationType.GetName(Rating)); end; const cRatingPositive = [TRating.Perfect, TRating.OK, TRating.Acceptable]; cRatingNegative = [TRating.NotGoodEnough, TRating.Bad, TRating.TotalShit]; procedure HandleRating(Rating: TRating); begin if Rating in cRatingPositive then begin // Handle positive rating part 1 ... // Handle specific rating case Rating of TRating.Perfect: ...; TRating.OK: ...; TRating.Acceptable: ...; else HandleIncompleteCase(Rating); end; // Handle positive rating part 2 ... end else if Rating in cRatingNegative begin // Handle negative rating part 1 ... // Handle specific rating case Rating of TRating.NotGoodEnough: ...; TRating.Bad: ...; TRating.TotalShit: ...; else HandleIncompleteCase(Rating); end; // Handle negative rating part 2 ... end else begin // Handle undefined rating ... end; end; |
AW: Delphi merkt nicht wenn ein case-Statement vollständig ist, oder?
Zitat:
|
AW: Delphi merkt nicht wenn ein case-Statement vollständig ist, oder?
Zitat:
Danke, das ist ein sehr schönes Beispiel :thumb: Aber trotzdem, ist es am Ende nicht fast das gleiche Ergebnis wie:
Delphi-Quellcode:
So richtig sehe ich den Mehrwert noch nicht.// Handle specific rating case Rating of //Positive rating TRating.Perfect: ...; TRating.OK: ...; TRating.Acceptable: ...; //Negative rating TRating.NotGoodEnough: ...; TRating.Bad: ...; TRating.TotalShit: ...; else HandleIncompleteCase(Rating); //<== OK, hier kann man nicht genau in Positive/Negative unterscheiden // Aber Du kommst ja trotzdem auf den richtigen, "falschen" case. // Wenn das "if x in" nicht passt, dann muss es auch nicht für "case x of" passen. end; type cRatingPositive = [TRating.Perfect..TRating.Acceptable]; // Wenn man es so definieren könnte, dann vielleicht. Ist das dann nicht eher ein Fall für ein Enum Set, mit allen seinen mathematischen Möglichkeiten? |
AW: Delphi merkt nicht wenn ein case-Statement vollständig ist, oder?
Zitat:
Diese ganze Diskussion ist eh nur theoretisch, da sie allenfalls case-Anweisungen ohne else-Zweig beträfe. Nur so könnte man das durchziehen ohne bestehenden Code plötzlich als fehlerhaft zu diffamieren. (Ich gehe dabei mal davon aus, dass der Entwickler weiß was er tut.) Insofern sind die im Code vorhandenen else-Zweige eigentlich auch obsolet und decken lediglich den Fall ab, dass die vorhergehende if-Anweisung klammheimlich erweitert und dabei die case-Anweisung nicht mitgezogen wird. Im Übrigen ist der Code auch nicht ganz korrekt in Bezug auf den record helper (und ein fehlendes then). Kommt davon wenn man Code im Web-Editor eingibt anstatt in der IDE. |
AW: Delphi merkt nicht wenn ein case-Statement vollständig ist, oder?
Zitat:
Der Vorab-Guard nimmt nur Performance und hilft meiner Meinung nach noch nicht mal bessere Lesbarkeit durch Gruppierung zu erzeugen. Ich bleibe bei Version HandleRating2. Trotzdem interessiert mich ein echtes Beispiel, wo das "if x in" gegenüber das "case x of" klar gewinnt, denn Ersteres nutze ich eigentlich so gut wie nie. Das liegt vielleicht daran, dass ich seit C sehr in das switch bzw. case of verliebt bin :oops: Das Beispiel habe ich mal entsprechend erweitert, ist ausführbar, um alle Fälle auszutesten:
Delphi-Quellcode:
type {$SCOPEDENUMS ON} //(1) Wegfall eines Enums ==> Compilierfehler // TRating = (undefined, Perfect, { OK, } Acceptable, NotGoodEnough, Bad, TotalShit); //(2) Zusätzliches, positives Enum NochWasGutes TRating = (undefined, Perfect, OK, NochWasGutes, Acceptable, NotGoodEnough, Bad, TotalShit); //(3) Zusätzliches, negatives Enum SehrSchlecht // TRating = (undefined, Perfect, OK, NochWasGutes, Acceptable, NotGoodEnough, Bad, SehrSchlecht, TotalShit ); //(4) Zusätzliches, negatives Enum am Ende SehrSchlecht OutOfRange // TRating = (undefined, Perfect, OK, NochWasGutes, Acceptable, NotGoodEnough, Bad, SehrSchlecht, TotalShit, OutOfRange ); //(5) Behandelt Undefined // TRating = (Undefined, Perfect, OK, NochWasGutes, Acceptable, NotGoodEnough, Bad, SehrSchlecht, TotalShit, OutOfRange ); TRatingHelper = record helper for TRating procedure HandleIncompleteCase; end; procedure TRatingHelper.HandleIncompleteCase; begin var LName := TRttiEnumerationType.GetName( Self ); raise Exception.Create('unhandled case for TRating: ' + LName ); end; const //cRatingPositive = [TRating.Perfect, TRating.OK, TRating.Acceptable]; //(A) Funktioniert nur, wenn die Ratings als SubRange definiert werden können cRatingPositive = [TRating.Perfect .. TRating.Acceptable ]; cRatingNegative = [TRating.NotGoodEnough .. TRating.TotalShit ]; //(B) Funktioniert noch besser, wenn die äußeren Grenzen mit High/Low definiert werden können // Starte NICHT ab Undefined bis zum letzten // cRatingPositive = [ Succ(Low(TRating)) .. TRating.Acceptable ]; // cRatingNegative = [ TRating.NotGoodEnough .. High(TRating), ]; //(C) Funktioniert noch besser, wenn die äußeren Grenzen mit High/Low definiert werden können // Starte NICHT ab Undefined bis zum letzten gültigen Enum // cRatingPositive = [ Succ(Low(TRating)) .. TRating.Acceptable ]; // cRatingNegative = [ TRating.NotGoodEnough .. TRating.TotalShit ]; procedure HandleRating1(Rating: TRating); begin if Rating in cRatingPositive then begin // Handle positive rating part 1 //<== (1) Kommt hier rein, wenn es einen neuen Positiven gibt // Handle specific rating case Rating of TRating.Perfect: ; TRating.OK: ; //<== (1) Compile-Error bei Wegfall eines Enums TRating.Acceptable: ; else Rating.HandleIncompleteCase; //(2)(3) Runtime-Error: "NochWasGutes", Wenn es einen neuen Positiven gibt end; // Handle positive rating part 2 end else if Rating in cRatingNegative then begin // Handle negative rating part 1 // Handle specific rating case Rating of TRating.NotGoodEnough: ; TRating.Bad: ; TRating.TotalShit: ; else Rating.HandleIncompleteCase; //(3)(4) Runtime-Error: "SehrSchlecht", Wenn es einen neuen Negativen gibt end; // Handle negative rating part 2 end else begin // (4)(5) Handle Undefined or OutOfRange rating Rating.HandleIncompleteCase; end; end; procedure HandleRating2(Rating: TRating); begin // Handle specific rating case Rating of TRating.Perfect: ; TRating.OK: ; //<== (1) Compile-Error bei Wegfall eines Enums TRating.Acceptable: ; // Handle specific rating TRating.NotGoodEnough: ; TRating.Bad: ; TRating.TotalShit: ; else Rating.HandleIncompleteCase; //(2)(3)(4)(5) Runtime-Error: "NochWasGutes", "SehrSchlecht", Zentral, für alle // Könnte notfalls hier in Gruppen zerlegt werden, was nur im Fehlerfall Performance braucht end; end; procedure Test; begin var LRating := TRating.NochWasGutes; // (2) // var LRating := TRating.SehrSchlecht; // (3) // var LRating := TRating.OutOfRange; // (4) // var LRating := TRating.Undefined; // (5) HandleRating1( LRating ); //RunTime-Fehler, wenn es was neues, Positives/Negatives gibt // HandleRating2( LRating ); //RunTime-Fehler, wenn es was neues, Positives/Negatives gibt end; |
Alle Zeitangaben in WEZ +1. Es ist jetzt 03:48 Uhr. |
Powered by vBulletin® Copyright ©2000 - 2025, Jelsoft Enterprises Ltd.
LinkBacks Enabled by vBSEO © 2011, Crawlability, Inc.
Delphi-PRAXiS (c) 2002 - 2023 by Daniel R. Wolf, 2024-2025 by Thomas Breitkreuz