goto-Statement hier elegant?

  • C#

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

    goto-Statement hier elegant?

    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*
    Und Gott alleine weiß alles am allerbesten und besser.

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

    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.
    Und Gott alleine weiß alles am allerbesten und besser.
    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“ ()

    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.
    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.
    _
    Und Gott alleine weiß alles am allerbesten und besser.
    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.

    φ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.
    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.
    @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...

    _
    Und Gott alleine weiß alles am allerbesten und besser.

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

    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---