Thomas Woelfers Baustatik Blog

Baustatik-Software und was sonst des Weges kommt

Wann ein bool ein bool ist - und wann ein Enum besser ist

Das größte Problem für booleans in C# ist die Lokalisierung: Wenn man erwarter, das ein bool im PropertyGrid mit deutschem Language Pack als "wahr/falsch" oder "ja/nein" angezeigt wird - dann täuscht man sich. Auch da taucht einfach "true/false" auf. Für eine Softwareentwicklungsumgebung mag das ja ok sein, für einen normalen Windows-Client ist es das wohl eher nicht.

Man muss den Kram also selbst lokalisieren. Und dabei stellt sich die Frage - hätte man nicht von vornherein besser einen Enum statt einen boolean genommen? Die Antwort lautet oft: Ja, genau.

Zusammen mit einer etwas ungünstigen Namensgebnung geht das Problem mit bools schon bei Methodenaufrufen los. Mal angenommen, man hätte die folgende Signatur:

void CalculateLogicalIntermediate( Point a, Point b, bool designFlag)

- dann hat man auf jeden Fall schon mal einen blöden Namen für den dritten Parameter gewählt. Was bitte ist denn ein "designFlag"? Und vor allem - muss man es auf true setzen, wenn das "design" denn stattfinden soll, oder doch auf false. Schwer zu sagen...

Schon viel besser ist es doch so:

enum DesignFlag { UseDesignMethology, DontUseDesignMethology }
void CalculateLogicalIntermediate( Point a, Point b, DesignFlag designFlag)

Wie findet man nun heraus, ob man für einen Parameter einen boolean nimmt oder nicht?

Eigentlich ganz einfach: Ein bool ist dann ein bool, wenn eine einfache Verneinung zum richtigen (vollständigen) Ergebnis führt. Und keiner, wenn nicht. Zum Beispiel:

bool isThicknessConstant;

Wenn die Dicke nun nicht konstant ist - wie ist sie denn dann definiert? Linear? Qudaratisch? Wenn isThicknessConstant=false, dann muss man erst noch die "echte" Art und Weise ermitteln - eine einfache Verneinung reicht also nicht aus, um zum vollständigen Ergebnis zu kommen. Die richtige Art wäre also

Enum ThicknesDefintion { Constant, Linear, Cubic, Unknown }

Comments (7) -

  • Floyd (Peter Becker)

    10/11/2006 5:55:32 AM |

    Im Bezug auf den Sachverhalt mit dem DesignFlag und der Namesgebung. Wäre in diesem Fall nicht der Variablenname für den dritten boolschen Wert

    "UseDesignMethologyEnable" oder gar "UseDesignMethologyDisable" vollkommen ausreichend?

    (was dem Punkt mit der Verneinung korrekt entspricht)

    Gruß Floyd

  • Thomas Wölfer

    10/11/2006 7:02:42 AM |

    Das Problem mit "UseDesignMethologyEnable" ist, das das nicht mal ein Wort ist. Konstrukte wo man künstliche ein "Enable" oder "Disable" hinten dranhängt um die Bedeutung zu erziele´n die man will, sind nicht wirklich nach meinem Geschmack.

    Aber mal angenommen, man setzt sich über derlei stilistische Spitzfindigkeiten hinweg: Ich sehe da immer noch zwei echte Probleme. "UseDesignMethologyEnable" - hier haben wir gleich zwei Begriffe, die verneint werden können. Wenn man das nun auf "false" setzt, ist dann das "Use" verneint, oder das "Enable"? Oder beides? Mir scheint, eine Verneinung ist hier alles andere als klar.

    Zweitens: Nehmen wir mal an, mal wollte das Ding irgendwo in einem Propertygrid lokalisieren. Das würde dann vermutlich so aussehen: "Benutzung der Entwurfsmethodik aktivieren - Wahr/Falsch". Wäre das hier nicht viel besser: "Entwurfsmethodik: Verwenden/Nicht verwenden"? (Wahr/Falsch ist die allgemeine lokalisierung für den boolean, "Verwenden/Nicht verwenden" ist die viel leichter anpassbare für den Enum.)

  • Floyd (Peter Becker)

    10/11/2006 7:32:59 AM |

    Hmm ich kann deiner Argumentation folgen.

    Zu Punkt eins: "UseDesignMethologyEnable" ... oky das "Use" kann man ja auch weglassen Laughing... für ne API denk ich wäre das vollkommen ausreichend zumal dann jeder etwas damit anfangen kann ohne sich die Parameterbemerkung anschauen zu müssen.

    Zu Punkt zwei: An der Stelle ist die Methodik mit den Enums sicherlich die etwas bessere. Rein theoretisch könnte mann ja auch einen Mapper für die boolschen Wert zugehörig zum Kontext schreiben. Dieser Mapper kann dann sogar über die Localisierungsressourcen seine Strings beziehen. Die Lösung fänd ich sogar noch eleganter, vorallem für mehrsprachige Programme. Ich weiß nicht ob das das Propertygrid auch unterstützt. Verwende Grids allgemein sehr selte da ich viel auf ASP.Net basis mache und dort mit Repeatern arbeite. Die Grid's sind mir dort zu unflexibel.

    Letztendlich wohl eher ne Geschmackssache.. Wobei ich glaube das ein Enum mehr Ressourcen frist als ein Boolen. Weil für ein enum mindestens Byte als Datentyp verbraucht wird, ein Boolschenwert jedoch nur ein Bit verbraucht oder täusch ich mich da?

  • Floyd (Peter Becker)

    10/11/2006 11:22:45 AM |

    Oky zum Punkt zwei: ich geb mich geschlagen ^^ man lernt ja gern was dazu.

    Was meinst du mit "direkt" lokalisierbar. Das heißt meines erachtens nach das du das Programm einmal für Deutsch, einmal für Englisch, etc. kompilieren musst und jedes mal die enums anfassen willst?! Wenn das war ist würde ich den Weg den ich beschrieben habe für mehrsprachige Applikationen(!!!) bevorzugen. Macht zwar mehr Arbeit aber ich hätte keine Lust bei jedem neuen Release für jede Sprache den Quellcode nochmal anpassen zu müssen.

    Ich bezieh mich dabei jedoch nur auf meine persönliche Meinung.

    Nungut, trotzdem danke für den Interessanten Artikel. Hoffentlich folgen weiterhin noch viele mehr ^^

  • Thomas Wölfer

    10/11/2006 11:33:44 AM |

    >> Das heißt meines erachtens nach das du das Programm einmal für Deutsch, einmal für Englisch, etc. kompilieren musst und jedes

    Nein, natürlich nicht. Das macht man so: Man leitet einen TypeConverter von EnumConverter ab. Der behandelt dann ConvertFrom/To string und liefert dabei die lokalisierten Strings aus der zur locale passenden Resource-Assembly (Die Resource-IDs können aus dem FQN der Enum-Member synthetisiert werden, d.h. man kann den gleichen Converter für alle Enums verwenden.). Den Converter hängt man dann an seine Enums (Was bei bool nur auf Property-Ebene, nicht aber auf Typ-Ebene geht, und daher viel mehr Arbeit ist): Kommt eine Spache hinzu, braucht man nur eine ensprechende Assembly mit den passend übersetzten String-Resourcen.

    Den Quellcode mehrfach zu übersetzen oder gar anzufassen ist natürlich nicht sinnvoll... Smile

  • Floyd (Peter Becker)

    10/11/2006 11:46:41 AM |

    Nur so zum Verständnis:

    1. Der TypeConverter entspricht doch in dem Fall einen Mapper oder?
    --
    So ich hab mir mal die MSDN zu rate gezogen. Man will ja fachlich korrekte Kommentare posten ^^

    Meine Frage kann ich mir also selbst beantworten: Ja

    Die Idee mit dem TypeConverter find ich garnicht schlecht. Dann hab ich aber doch noch eine Frage. Warum für einen boolschen Wert dann ein Enum verwenden? Der BooleanConverter würde es doch auch tun oder etwa nicht?

    msdn2.microsoft.com/.../...l.booleanconverter.aspx

    Bitte fass meine Postings net als Besserwiserei oder Angriff auf.. Ich versuch nur dazuzulernen.

Comments are closed