goto-Statement hier elegant?

  • C#

Es gibt 20 Antworten in diesem Thema. Der letzte Beitrag () ist von φConst.

    goto-Statement hier elegant?

    Neu

    Hi,
    im Moment arbeite_ ich an einen neuen Parser für den HtmlRenderer(siehe ShowRoom).

    Folgende Methode extrahiert_ die einzelnen Tags und ihre Inhalte:

    Spoiler anzeigen

    C#-Quellcode

    1. private static void _Format(string BeginTag, ref string Content)
    2. {
    3. int _AppearanceCounter = 0;
    4. int n0 = BeginTag.Length + 1;
    5. int n1 = BeginTag.Length + 2;
    6. for (int i = 0; i < Content.Length; i++)
    7. {
    8. string sub0 = "";
    9. string sub1 = "";
    10. if (i + n0 >= Content.Length)
    11. sub0 = Content.Substring(i, Content.Length - i);
    12. else sub0 = Content.Substring(i, n0);
    13. if (sub0.Equals("<" + BeginTag))
    14. {
    15. _AppearanceCounter++;
    16. if (_AppearanceCounter == 1)
    17. Content = Content.Insert(i + n0, (_AppearanceCounter - 1) + "");
    18. }
    19. if (i + n1 >= Content.Length)
    20. sub1 = Content.Substring(i, Content.Length - i);
    21. else sub1 = Content.Substring(i, n1);
    22. if (sub1.Equals("</" + BeginTag))
    23. {
    24. _AppearanceCounter--;
    25. if (_AppearanceCounter == 0)
    26. {
    27. Content = Content.Insert(i + n1, (_AppearanceCounter) + "");
    28. return;
    29. }
    30. }
    31. }
    32. }
    33. public static HtmlTag[] GetTags(string Content)
    34. {
    35. string beginTag = "";
    36. string endTag = "";
    37. string attribute = "";
    38. List<HtmlTag> _Tags = new List<HtmlTag>();
    39. bool _Begin = false;
    40. bool _Attribute = false;
    41. for (int i = 0; i < Content.Length; i++)
    42. {
    43. char c = Content[i];
    44. switch (_Begin)
    45. {
    46. case true:
    47. if (c == '>')
    48. {
    49. if (Program.Tags.Contains(beginTag))
    50. endTag = beginTag;
    51. HtmlTag tag = new HtmlTag()
    52. {
    53. BeginTag = beginTag,
    54. EndTag = endTag,
    55. Attribute = attribute
    56. };
    57. _Tags.Add(tag);
    58. if (string.IsNullOrEmpty(endTag))
    59. {
    60. Content = Content.Replace("<" + beginTag + ">", "");
    61. goto reset;
    62. }
    63. #region WithEndTag
    64. string _begin = "<" + beginTag + "0" + attribute + ">";
    65. string _end = "</" + endTag + "0>";
    66. _Format(beginTag, ref Content);
    67. tag.Content = Content.Substring(Content.IndexOf(_begin) + _begin.Length, Content.IndexOf(_end) - i - 2);
    68. Content = Content.Replace(_begin + tag.Content + _end, "");
    69. #endregion
    70. reset:
    71. #region Reset
    72. _Begin = false;
    73. i = -1;
    74. beginTag = "";
    75. attribute = "";
    76. _Attribute = false;
    77. #endregion
    78. continue;
    79. }
    80. if (c == ' ')
    81. {
    82. _Attribute = true;
    83. }
    84. if (!_Attribute)
    85. beginTag += c;
    86. else attribute += c;
    87. break;
    88. case false:
    89. if (c == '<')
    90. {
    91. _Begin = true;
    92. }
    93. break;
    94. }
    95. }
    96. return _Tags.ToArray();
    97. }


    Wenn ein Tag keinen korrespondierenden End-Tag hat wird das Parsen des Contents übersprungen.
    Damit jedoch die Prozedur kontinuieren kann, müssen folgende Werte gesetzt werden:

    _Begin = false;
    i = -1;
    beginTag = "";
    attribute = "";
    _Attribute = false;

    Und genau diese Region kann über die Sprungmarke "reset" erreicht werden, siehe dazu:
    goto-Statement hier elegant?

    Ist das elegant, oder doch lieber eine inLine-Methode?

    Lieben Dank.

    *Topic verschoben*
    DotNETWork (Generische Tcp-Klasse, verschlüsselt!)
    MonogameMinecraftClone (Minecraft-Klon)
    NeuroEvolution (Implementation zweier Lernmethoden für neuronale Netze)

    Dieser Beitrag wurde bereits 1 mal editiert, zuletzt von „Marcus Gräfe“ ()

    Neu

    Entweder meine müden Augen täuschen mich, oder aber du vergisst das Wörtchen else in deinen Überlegungen.

    Außerdem ein switch-case für eine bool variable? Warum kein if-else ?
    Post-AGB:
    §1 Mit dem Lesen dieses Posts stimmst du den AGB unverzüglich zu
    §2 Ein Widerruf muss innerhalb von 3 Sekunden nach Lesen des Hauptbestandteil des ersten jemals gelesenen Posts erfolgen
    Abs.1 Die Signatur zählt nicht zum Hauptbestandteil des Posts
    §3 Ein erfolgreicher Widerruf zwingt zu einem Besuch bei einem Hypnotiseur oder Neurochirurg, sodass der gelesene Text aus den Erinnerungen entfernt werden kann
    Abs.1 Die Kosten und Risiken sind jeweils selbst zu tragen

    Neu

    LOL, else. Stimmt. Danke.

    Addendum:
    @wolfi_bayern
    Naja, ein nogo ist das nicht unbedingt.. Wie sonst willst du verschachtelte for-loops abbrechen?

    @EaranMaleasi
    Finde das lesbarer.
    DotNETWork (Generische Tcp-Klasse, verschlüsselt!)
    MonogameMinecraftClone (Minecraft-Klon)
    NeuroEvolution (Implementation zweier Lernmethoden für neuronale Netze)

    Neu

    Also wenn es um Performance geht würde ich sagen inLine, dann spart man sich den Sprungbefehl. Ist ja auch sonst eigentlich die gängige Praxis oder nicht? Ich wäre glaube ich gar nicht auf ein goto gekommen.
    EDIT: Ups, nicht gesehen, dass schon drei mal darauf geantwortet wurde in der Zeit in der ich den Thread offen hatte :D

    EDIT 2: Jetzt nach dem Lesen: Bricht man for-loops nicht normal mit einer Austrittsbedigung oder im Zweifel break? Und ich sehe gerade nicht wie ein Else da hilft kann auch sein, dass es einfach zu spät ist :/

    EDIT 3: Jetzt seh' ichs :D

    Dieser Beitrag wurde bereits 2 mal editiert, zuletzt von „xd-franky-5“ ()

    Neu

    Hi,
    wie willst du

    C-Quellcode

    1. for(int i = 0; i < a; i++)
    2. {
    3. for(int j = 0; j < b; j++)
    4. {
    5. for(int k = 0; k < c; k++)
    6. {
    7. // do some stuff
    8. }
    9. }
    10. }

    abbrechen?
    DotNETWork (Generische Tcp-Klasse, verschlüsselt!)
    MonogameMinecraftClone (Minecraft-Klon)
    NeuroEvolution (Implementation zweier Lernmethoden für neuronale Netze)

    Neu

    Ja gut da wäre es vielleicht okay, aber man könnte i = a, j = b und k = c setzen in der innnersten loop oder einen Boolean der von allen geprüft wird und sie dann gegebenenfalls abbricht. Oder am besten mit Return arbeiten.

    Neu

    Das wäre zwar eine Möglichkeit, mit goto lässt sich das imo eleganter lösen:


    C-Quellcode

    1. for(int i = 0; i < a; i++)
    2. {
    3. for(int j = 0; j < b; j++)
    4. {
    5. for(int k = 0; k < c; k++)
    6. {
    7. // do some stuff
    8. goto exit;
    9. }
    10. }
    11. }
    12. exit:



    Return hilft da nicht unbedingt, wenn die for loops nur eine Prozedur repräsentieren, und der relevante Code nach den loops kontinuiert.
    _
    DotNETWork (Generische Tcp-Klasse, verschlüsselt!)
    MonogameMinecraftClone (Minecraft-Klon)
    NeuroEvolution (Implementation zweier Lernmethoden für neuronale Netze)

    Neu

    Wie gesagt, wäre okay wenn man sein Problem nicht ohne Abbruch hin bekommt :) Achja und man könne ja anonyme Funktionen verwenden je nach Programmiersprache finde ich das sogar ganz elegant, bei C# vielleicht nicht ganz so.

    Neu

    Methoden-Aufrufe sind perfomance-technisch nicht immer günstig(insbesondere bei nested loops), zumindest in c sharp nicht.

    Grüße
    DotNETWork (Generische Tcp-Klasse, verschlüsselt!)
    MonogameMinecraftClone (Minecraft-Klon)
    NeuroEvolution (Implementation zweier Lernmethoden für neuronale Netze)

    Neu

    Kommt darauf an, ob die vom compiler "ge-inlined" werden. Wenn ja, hast du nacher im IL afaik keinen Methodenaufruf mehr, sondern die Methode wurde komplett in die andere kopiert.
    Post-AGB:
    §1 Mit dem Lesen dieses Posts stimmst du den AGB unverzüglich zu
    §2 Ein Widerruf muss innerhalb von 3 Sekunden nach Lesen des Hauptbestandteil des ersten jemals gelesenen Posts erfolgen
    Abs.1 Die Signatur zählt nicht zum Hauptbestandteil des Posts
    §3 Ein erfolgreicher Widerruf zwingt zu einem Besuch bei einem Hypnotiseur oder Neurochirurg, sodass der gelesene Text aus den Erinnerungen entfernt werden kann
    Abs.1 Die Kosten und Risiken sind jeweils selbst zu tragen

    Neu

    φConst schrieb:

    Methoden-Aufrufe sind perfomance-technisch nicht immer günstig(insbesondere bei nested loops), zumindest in c sharp nicht.
    Das scheint mir in diesem Falle malwieder vollkommen irrelevant.
    Wen interessiert, ob ein Methodenaufruf stattfund, wenn im nächsten Atemzug 100*100*100 Schleifenelemente durchgeschleift werden?
    Der Methodenaufruf erfolgt ja nicht im innern der (hier gezeigten) 3-dimensionalen Schleife.

    Daher die einzig belangvolle Frage, ob die Alternatibe mit der anonymen Methode besser überschaubaren Code erbringt als das goto.
    Meine Meinung dazu: Es hält sich die Waage.

    Neu

    Es kann durchaus vorkommen das mehrere tausende Male die anonyme "Clear -Methoden aufgerufen werden müsste. (Zumindest beim Parsen)

    Aber ohnehin tat's else.
    _
    DotNETWork (Generische Tcp-Klasse, verschlüsselt!)
    MonogameMinecraftClone (Minecraft-Klon)
    NeuroEvolution (Implementation zweier Lernmethoden für neuronale Netze)

    Neu

    und das könntest du iwie durch ein goto vermeiden??

    Wenn nicht, dann ist die Performance-Frage hier nochmal so irrelevant.
    Ich frag mich, wann die Leuts mal kapieren, wann Performance-Fragen relevant sind, und wann nicht.
    Es ist ja ein völlig einfacher Gedanke (Stichwort "Flaschenhals") - nur muss man ihn auch denken.

    Neu

    @ErfinderDesRades

    Wenn es die Möglichkeit eines "else" nicht gegeben hätte sicher. Wenn Seiten wie Google geparst werden sollen, sind Methoden-Calls ein bottleneck: Probier's selbst: Mach eine for Schleife bis 1 000 000 und vergleiche die Perfomance von goto mit mit Methoden-Call..

    Keine Ahnung wieso alle so gegen goto sind, ich finde es in manchen Fällen lesbarer und eleganter.

    @Rikudo

    Völlig übertrieben mit dem delegaten. Dijkstra hatte sicher nicht die Absicht als er gegen goto wetterte solche Umwege vorzuschlagen...

    _
    DotNETWork (Generische Tcp-Klasse, verschlüsselt!)
    MonogameMinecraftClone (Minecraft-Klon)
    NeuroEvolution (Implementation zweier Lernmethoden für neuronale Netze)

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

    Neu

    goto ist wie hier schon ein paar mal angemerkt bestimmt nicht Grundsätzlich böße. Es gibt nur einige Wenige Fälle wo es sinnvoll ist. Und es kann mir keiner erzählen, dass weder syntaktisch, noch programflow, noch performance noch whatever technisch eine Zusätzliche abbruch Bedingung bei nested loops schöner sei...

    ErfinderDesRades schrieb:

    Ich frag mich, wann die Leuts mal kapieren, wann Performance-Fragen relevant sind, und wann nicht.

    Darfst dabei vergessen, dass immer noch(selbst mit .Net Core - leider) gilt, dass sich C# programmierer da immer noch weniger Freiraum haben als viele andere und eben einige Optimierungen selbst vornehmen müssen. :P
    Und ich kenne das Bottleneck von Methodenaufrufen und das muss auch nicht in ner Schleife sein, wie @TE angemerkt hat, passiert es hier auch ziemlich Oft, weil webseiten in der heuten Zeit eben meist nicht in Web 0.1 alpha geschrieben werden.

    Inlining findet btw. auf Jitter ebene Statt und nicht beim erzeugen des IL-Codes...

    @seh: kann man nicht, aber es gibt Fälle in denen locale functions tatsächlich geinlined werden können, wenn man z.B. keine variablen außerhalb dieser anonymen methode verwendet(bis auf übergabeparameter), das andere Zeugs wird nehmlich über eine eigens erstellte Klasse übergeben, durch welche inlining leider verhindert wird. Delegaten und somit auch anonyme methoden können das meines Wissens jedoch immer noch nicht(ich warte schon lange darauf)...

    @φConst: ganz allgemein würde ich persönlich das lieber mit einem lexer und anschließendem parser schritt machen. Würde das ganze strukturierter, leichter erweiterbar, leichter streambar, vmtl. auch besser lesbar machen. Und das vorgehen gegen Syntaktische Fehler dürfte denke ich auch einfacher gehen(ebenso wie das ignorieren dieser Fehler natürlich^^)
    Ich wollte auch mal ne total überflüssige Signatur:
    ---Leer---