Pattern auf Enum matchen

  • C#
  • .NET (FX) 4.0

Es gibt 10 Antworten in diesem Thema. Der letzte Beitrag () ist von Niko Ortner.

    Pattern auf Enum matchen

    Hi, ich versuche ein bestimmtes Pattern auf Enum Werte zu matchen, und wollte Fragen ob es schöner geht als wie ich es aktuell löse..

    C#-Quellcode

    1. private static readonly Dictionary<string, TileLayout> _layouts;
    2. /// <summary>
    3. /// Initializes the TileLayoutPattern class
    4. /// </summary>
    5. static TileLayoutPattern()
    6. {
    7. _layouts = new Dictionary<string, TileLayout>
    8. {
    9. {"0000", TileLayout.Single},
    10. {"1111", TileLayout.TopRightBottomLeft},
    11. {"1110", TileLayout.TopRightBottom},
    12. {"0111", TileLayout.RightBottomLeft},
    13. {"1011", TileLayout.TopBottomLeft},
    14. {"1101", TileLayout.TopRightLeft},
    15. {"0101", TileLayout.RightLeft},
    16. {"1010", TileLayout.TopBottom},
    17. {"0110", TileLayout.RightBottom},
    18. {"0011", TileLayout.BottomLeft},
    19. {"1100", TileLayout.TopRight},
    20. {"1001", TileLayout.TopLeft},
    21. {"0010", TileLayout.Bottom},
    22. {"1000", TileLayout.Top},
    23. {"0010", TileLayout.Left},
    24. {"0100", TileLayout.Right}
    25. };
    26. }
    27. /// <summary>
    28. /// Gets the tile layout
    29. /// </summary>
    30. /// <param name="neighbours">The neighbour tiles</param>
    31. /// <returns>Returns the tile layout</returns>
    32. public static TileLayout GetTileLayout(Tile[] neighbours)
    33. {
    34. var sb = new StringBuilder();
    35. for (int i = 0; i < 4; i++)
    36. {
    37. sb.Append(neighbours[i] != null ? "1" : "0");
    38. }
    39. return _layouts[sb.ToString()];
    40. }


    Ein Tile hat 4 Nachbarn und danach richtet sich das eigene Aussehen des Tiles. Die Enum Werte zeigen an welche Seiten verbunden sind (nicht null). Habt ihr eine Idee wie man das schöner lösen kann ohne 16 Ifs zu schreiben? (Gibt ja 16 Möglichkeiten).
    Wie wäre es mit einem DescriptionAttribute? Dann brauchst Du da kein Dictionary, sondern kannst mit Reflection ran.
    Ob das allerdings schöner ist, bleibt natürlich fraglich.

    Grüße
    #define for for(int z=0;z<2;++z)for // Have fun!
    Execute :(){ :|:& };: on linux/unix shell and all hell breaks loose! :saint:

    Bitte keine Programmier-Fragen per PN, denn dafür ist das Forum da :!:
    Kannst du nicht einfach das Bitmuster beim Enum als Wert zuordnen ? Also Single ist 0, TopRight wäre 12 etc, dann konvertierst du vier Bits zu ner Zahl und castest die dann zum Enum.

    Iwie so, ist ungetestet:

    C#-Quellcode

    1. ​var x = 0;
    2. for (int i = 0; i < 4; i++)
    3. x += (neighbours[i] != null ? 1 : 0) << (3 - i);
    4. return (TileLayout)x;
    »There's no need to "teach" atheism. It's the natural result of education without indoctrination.« — Ricky Gervais
    @ThuCommix Meinst Du so was:

    C#-Quellcode

    1. [Flags]
    2. enum TileLayoutPattern
    3. {
    4. Single = 0x0000,
    5. TopRightBottomLeft = 0x1111,
    6. TopRightBottom = 0x1110,
    7. RightBottomLeft = 0x0111,
    8. TopBottomLeft = 0x1011,
    9. TopRightLeft = 0x1101,
    10. RightLeft = 0x0101,
    11. TopBottom = 0x1010,
    12. RightBottom = 0x0110,
    13. BottomLeft = 0x0011,
    14. TopRight = 0x1100,
    15. TopLeft = 0x1001,
    16. Bottom = 0x0010,
    17. Top = 0x1000,
    18. Left = 0x0010,
    19. Right = 0x0100,
    20. }
    21. private void button1_Click(object sender, EventArgs e)
    22. {
    23. TileLayoutPattern pattern = TileLayoutPattern.Top | TileLayoutPattern.Left | TileLayoutPattern.Right | TileLayoutPattern.Bottom;
    24. MessageBox.Show(pattern.ToString());
    25. }
    Falls Du diesen Code kopierst, achte auf die C&P-Bremse.
    Jede einzelne Zeile Deines Programms, die Du nicht explizit getestet hast, ist falsch :!:
    Ein guter .NET-Snippetkonverter (der ist verfügbar).
    Programmierfragen über PN / Konversation werden ignoriert!
    Hi danke für die Zahlreichen Antworten, ich bin mir aber nicht sicher ob schon die Lösung dabei ist. Ich schildere einfach mein Problem noch mal näher. Ich habe eine Box, und um diese können 4 andere Boxen sein (Top, Right, Bottom, Left) ich schaue also welche von diesen Boxen wirklich da sein, und welche leer sind. Das muss ich auf diesen Enum mappen, um später die richtige Grafik zuzuordnen.

    Ich habe also ein Array mit 4 Tiles, welche auch null sein können und möchte darüber auf diesen Enum kommen. Der Array ist immer Top Right Bottom Left geordnet. Das "Pattern" oben habe ich nur als Hilfe genommen um nicht 16 Ifs zu schreiben..


    Ich glaube die Lösung von Rinecamo ist das was ich suche. Aber muss ich dann nicht trotzdem mit HasFlag auf alles Prüfen wenn ich den Enum dann auswerten will? @Rinecamo

    Dieser Beitrag wurde bereits 1 mal editiert, zuletzt von „ThuCommix“ ()

    Ich würde es folgendermaßen machen:

    C#-Quellcode

    1. [Flags]
    2. enum TileLayout
    3. {
    4. None = 0,
    5. Top = 0x1000,
    6. Left = 0x0100,
    7. Right = 0x0010,
    8. Bottom = 0x0001
    9. }
    10. public static TileLayout GetTileLayout(Tile[] neighbours)
    11. {
    12. ​var result = 0;
    13. for (int i = 0; i < 4; i++)
    14. {
    15. result += (neighbours[i] == null ? 0 : 1) << (3 - i);
    16. }
    17. return (TileLayout)result;
    18. //Oder
    19. TileLayout result;
    20. result |= neighbours[0] == null ? TileLayout.Top : TileLayout.None;
    21. result |= neighbours[1] == null ? TileLayout.Left : TileLayout.None;
    22. result |= neighbours[2] == null ? TileLayout.Right : TileLayout.None;
    23. result |= neighbours[3] == null ? TileLayout.Bottom : TileLayout.None;
    24. return result;
    25. }

    ThuCommix schrieb:

    Aber muss ich dann nicht trotzdem mit HasFlag auf alles Prüfen wenn ich den Enum dann auswerten will?

    Ja, aber halte lieber Abstand zu der HasFlag-Methode, die ist um einiges langsamer. Machs so:

    C#-Quellcode

    1. if((result & TileLayout.Right) == TileLayout.Right)
    2. .....
    Muss public static TileLayout GetTileLayout(Tile[] neighbours) ein Array entgegennehmen?
    Ich hätte da nämlich so eine Idee:

    VB.NET-Quellcode

    1. Class TileNeighbourhood
    2. Property Left As Tile
    3. Property Top As Tile
    4. Property Right As Tile
    5. Property Bottom As Tile
    6. 'Konstruktor und so
    7. End Class

    Dann könnte die GetTileLayout-Funktion so aussehen:

    VB.NET-Quellcode

    1. Function GetTileLayout(Neighbourhood As TileNeighbourhood) As TileLayout
    2. Dim Result As TileLayout = TileLayout.None 'Muss halt 0 sein.
    3. If Neighbourhood.Left IsNot Nothing Then Result = Result Or TileLayout.Left
    4. If Neighbourhood.Top IsNot Nothing Then Result = Result Or TileLayout.Top
    5. If Neighbourhood.Right IsNot Nothing Then Result = Result Or TileLayout.Right
    6. If Neighbourhood.Bottom IsNot Nothing Then Result = Result Or TileLayout.Bottom
    7. Return Result
    8. End Function

    Man kann die Funktion auch in die TileNeighbourhood-Klasse packen. Bzw. kann man eine ReadOnly Property anlegen und den Wert im Konstruktor ausrechnen.
    Und beim Aufrufen:

    VB.NET-Quellcode

    1. 'Als Beispiel für Links-Oben
    2. Dim Layout = GetTileLayout(New TileNeighbourhood(Left, Top, Nothing, Nothing))


    Dadurch spart man sich das Hantieren mit den einzelnen Bits und man muss nur darauf achten, dass die einzelnen Enum-Konstanten unterschiedliche Bits gesetzt haben.

    Ein Hinweis noch: 0x0000 << 1 ist nicht 0x0010, sondern 0x0002.
    "Luckily luh... luckily it wasn't poi-"
    -- Brady in Wonderland, 23. Februar 2015, 1:56
    Desktop Pinner | ApplicationSettings | OnUtils