break; und continue frage

  • C#
  • .NET (FX) 4.5–4.8

Es gibt 46 Antworten in diesem Thema. Der letzte Beitrag () ist von BiedermannS.

    Unter den ersten Einträgen auf Google.
    u.arizona.edu/~rubinson/copyri…o_Considered_Harmful.html

    Als Programmierer solltest du Code schreiben der gut verständlich und wartbar ist und nicht einfach nur funktioniert :)
    SWYgeW91IGNhbiByZWFkIHRoaXMsIHlvdSdyZSBhIGdlZWsgOkQ=

    Weil einfach, einfach zu einfach ist! :D
    @BiedermannS:
    1. Siehe EDR
    2. du glaubst wirklich der C# Compiler optimiert das weg? Ganz bestimmt nicht. Compiler die gut optimieren können machen das, C# gehört eindeutig nicht dazu. Java ist da bereits besser und Java selbst ist immernoch ziemlich mißerabel darin.
    3. Das hier ist definitiv einer der Edge cases. Denn filterst du mehrmals, dann hast du zwar alles schön übersichtlich(mit goto auch gut lesbar), jedoch den langsamsten Algorithmus der Welt. Herzlichen Glückwunsch, jetzt hast du ein gutes Datenmodell, dass du nur für MiniAnwendungen verwenden kannst, das mit ein paar wenigen Datensätzen arbeiten kann.

    Edit:

    BiedermannS schrieb:

    Als Programmierer solltest du Code schreiben der gut verständlich und wartbar ist und nicht einfach nur funktioniert

    Dann zeig mal deinen Code dazu, dann bewerte ich mit meiner subjektivität das ganze

    Und zu deinem Artikel, entweder hab ich den falsch verstanden, oder der redet nie so richtig von tiefen Verschachtelungen und ziemlich allgemein, was man nur schwer auf alle Sprachen anwenden kann.
    Ich wollte auch mal ne total überflüssige Signatur:
    ---Leer---

    Dieser Beitrag wurde bereits 2 mal editiert, zuletzt von „jvbsl“ ()

    noch 'ne Dogmatik-Umdrehung - keine Begründung

    Konkret:

    BiedermannS schrieb:

    gut verständlich und wartbar


    Inwiefern sind diese 8 Zeilen:

    C#-Quellcode

    1. foreach (string username in lb_users.Items) {
    2. while (tmpN < sites + 1) {
    3. foreach (var vid in vobj.userVideoCollection) {
    4. if (bedingung) goto EXIT;
    5. }
    6. }
    7. }
    8. EXIT:
    ... schwerer verständlich/wartbar als diese 12?:

    C#-Quellcode

    1. foreach (string username in lb_users.Items) {
    2. bool exit = false;
    3. while (!exit && tmpN < sites + 1) {
    4. foreach (uservideos.UserVideoCollection vid in vobj.userVideoCollection) {
    5. if (DEINE_BEDINGUNG) {
    6. exit = true;
    7. break;
    8. }
    9. }
    10. }
    11. if (exit) break;
    12. }
    (wie gesagt: mehr zeilen, zusätzliche Variablen, zusätzliche Abfragen)

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

    @jvbsl
    zu 2.: Der C# Compiler ist schon ziemlich gut im optimieren.
    zu 3.: Das glaube ich kaum. Man kann auch gut leserliche Algorithmen schreiben die trotzdem schnell genug sind.

    ErfinderDesRades schrieb:

    und noch 'ne Umdrehung...

    Das war keine Umdrehung sondern ein Zusatz.

    Von den beiden Code Snippets die du gepostet hast ist keines wirklich zu bevorzugen, aber ohne zu wissen was das Ergbnis der Schleifen sein soll, kann ich dir hier leider keinen besseren Algorithmus präsentieren. Vielleicht kann der TE ja das Ziel des Codes posten, dann hol ich das gerne nach.
    SWYgeW91IGNhbiByZWFkIHRoaXMsIHlvdSdyZSBhIGdlZWsgOkQ=

    Weil einfach, einfach zu einfach ist! :D

    BiedermannS schrieb:

    Unter den ersten Einträgen auf Google.
    u.arizona.edu/~rubinson/copyri…o_Considered_Harmful.html


    Das ist aus einer Zeit, wo es noch üblich war sogar Funktionen/Prozeduren durch goto zu ersetzen (bzw. Prozeduren grade erst eingeführt worden waren).

    jvbsl schrieb:

    2. du glaubst wirklich der C# Compiler optimiert das weg? Ganz bestimmt nicht. Compiler die gut optimieren können machen das, C# gehört eindeutig nicht dazu. Java ist da bereits besser und Java selbst ist immernoch ziemlich mißerabel darin.


    Der C# Compiler (und auch der Java-Compiler) an sich optimiert kaum bzw. gar nicht. Der JIT Compiler aber schon ;) Hat den Vorteil, dass man direkt auf die Zielarchitektur optimieren kann.
    @Quadsoft: das ist mir schon klar, aber da die Optimierugen mehr Vorteile bringen müssen als die Optimierung selbst Zeit beansprucht, gehen nur sehr einfache Optimierungen und dabei muss man sogar sagen, dass viele da auch nicht funktionieren.

    Z.B. % (2^n) wird nicht durch & (2^n - 1) ersetzt. Zusätzlich bin ich mir sicher, dass es keine Architektur gibt auf der das keine Optimierung darstellt, dasselbe gilt für obiges.
    Es wäre schön, wenn C# wenigstens die Möglichkeit bieten würde solche Optimierungen zu Aktivieren, am liebsten natürlich zur Runtime. Denn manchmal weiß halt der Entwickler doch was er braucht^^

    Edit:
    @BiedermannS
    2. Tut mir leid dich enttäuschen zu müssen aber C# ist immernoch eine der Hauptsprachen, die am schlechtesten optimieren kann.
    3. Hab ich nie was anderes behauptet, aber wie du bei @ErfinderDesRades siehst ist das erste eindeutig besser lesbar und zusätzlich performanter. Aber das was du vorgeschlagen hattest mit mehrmals filtern wird niemals an die Performance von 1. herankommen, es sein denn du hast einen super tollen Compiler der aus deinem Code, den Code 1 macht(Was C# in den nächsten 5 Jahren bestimmt nicht hinbekommt)
    Ich wollte auch mal ne total überflüssige Signatur:
    ---Leer---
    Wie siehts mit .NET Native aus? Immerhin wird hier ja auch AOT kompiliert. Weis da jemand was darüber wie dort optimiert wird?
    Ms behauptet hier folgendes:

    Microsoft schrieb:

    .NET Native is able to bring the performance benefits of C++ to managed code developers because it uses the same or similar tools as C++ under the hood, as shown in this table.

    Also ich hab hier grad einen Test gemacht. Einmal mit zwei for loops und einmal mit LINQ.
    Die LINQ Version ist nicht nur etwas schneller, sonder drückt auch genauer aus was passieren soll, anstatt wie es passieren soll.

    Also würde ich mal behaupten dass es sehr wohl optimiert wird.

    Soweit ich weiß ist LINQ lazy. Dadurch kannst du mehrere Filter zusammenhängen, ohne dass sich das zu sehr auf die Performance auswirkt.
    SWYgeW91IGNhbiByZWFkIHRoaXMsIHlvdSdyZSBhIGdlZWsgOkQ=

    Weil einfach, einfach zu einfach ist! :D
    @BiedermannS

    Das hat aber nichts mit der Optimierung durch den Compiler zu tun... Die ganzen LINQ methoden sind mittels Co-Routinen implementiert (yield), aber das ist ja keine Optimierung sondern ein Sprachfeature.

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

    ErfinderDesRades schrieb:

    C#-Quellcode

    1. if (bedingung) goto EXIT;
    Das würde ich dann wohl in ein return; umbauen.
    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!
    Heyho,
    erstmal zu @BiedermannS:
    Ja der Code sollte wartbar sein ich weiß nicht ob das auf mich bezogen war allerdings habe ich für meine vorhaben
    immer erst eine "dummy" Anwendung in dem ich die Sachen erstmal nur funktionsfähig mache und teste, anschließend
    schreib ich da aber nochmal neu und strukturiere dann richtig... mir ist halt wichtig das ich erst die Funktionalität sicherstelle
    bevor es schön aussieht... kenne viele Leute die wollen das es schön aussieht und dann funktioniert nichts ;)

    und dann zu meinem code
    ich weiß nicht ob ich zu prozedual denke oder nicht denn meine Daten kommen von einer Website und dort in dem Quelltext stehen
    die Daten in einem JSON-String.
    Ich habe natürlich die JSON Daten in einer Klasse nachgebaut und dort rein geladen.
    Nun bekomme ich aber (Deshalb die 3 Schleifen) einmal die Liste der Abbonierten User (lb_users (listbox)).
    Diese liste nutze ich ja in der ersten foreach damit ich auf jeder Videoseite des Users (xxxxx.com/username/videos)
    die Anzahl der Seiten ( das ist die While schleife ) habe und dann gehe ich pro seite ( die letzte foreach ) die Uservideos durch.
    Dort ist es so das in dem JSON String immer das aktuellste VIDEO der erste Eintrag ist.
    Heißt wenn das erste Video schon in meiner Datenbank ist brauch ich nicht weiter schauen und gehe direkt
    zum nächsten User.
    Weiß nicht wie ich das verkürzen könnte ?
    Denn ALLE 3 Schleifen haben für mich ihre Berechtigung da zu sein denn ich gehe ja ALLE User durch - dann die SEITE und auf der SEITE die VIDEOS.
    Bin gerne offen für tipps das ich da weniger schleifen brauche aber ich denke bei den gegebenen umständen geht da nichts anderes.
    (ich habe kein Zugriff auf irgendeine API der Seite noch auf die Datenbank der Seite - habe aber die erlaubnis den Quelltext auszulesen automatisiert)

    sorry für die wall of text das eskaliert hier ja richtig :P
    Grüße , xChRoNiKx

    Nützliche Links:
    Visual Studio Empfohlene Einstellungen | Try-Catch heißes Eisen

    xChRoNiKx schrieb:

    Weiß nicht wie ich das verkürzen könnte ?
    Ohne den Code dazu zu sehen kann man nix sagen.
    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!

    BiedermannS schrieb:

    ErfinderDesRades schrieb:

    und noch 'ne Umdrehung...

    Das war keine Umdrehung sondern ein Zusatz.
    Aber leider ein Zusatz ohne zusätzliche Information/Argumentation. Dass man gut verständlichen und wartbaren Code schreiben soll, ist ja längst Konsens.

    BiedermannS schrieb:

    ...Von den beiden Code Snippets...wissen was das Ergbnis der Schleifen sein soll...
    Hmm - das Ergebnis findich nun grad irrelevant für den Vergleich.
    Die Schleifen verhalten sich absolut identisch, nämlich es ist ein foreach in eine while in ein foreach eingeschachtelt, und wenn inne innere foreach eine Bedingung zutrifft werden alle 3 Schleifen verlassen, und der Code setzt dahinter fort.
    Mittm Goto ist dieser Workflow ausdrücklich hingeschrieben: if (bedingung) goto EXIT
    In der goto-freien Variante ist der Workflow doch deutlich komplizierter - eine Hilfsvariable ist vonnöten, diese ist zu setzen, und dann folgen 3 Tests dieser Variablen - in jeder Schleife einer.

    Wie gesagt - was das Ergebnis davon ist, ist für die Betrachtung nicht wichtig. Etwa vergleichbare Schleifen könnte man schreiben für eine Suche in einem 3-Dimensionalen Array.
    Jeder LinQ Code lässt sich anders und performanter programmieren. Ja es werden gewisse Optimierungen vorgenommen, aber sehr oft ist vieles gar nicht möglich, LinQ macht oft auch Heap Allokationen, welche sich bei einem einfachen Test gar nicht auswirken und erst später bemerkbar werden, sich aber durch ausgeschriebenen Code Komplett verhindern lässt.
    Und für die Behauptung du hast den Unterschied getestet und LinQ war schneller @BiedermannS hätte ich gerne den Code von beiden getesteten Varianten, die Daten mit denen getestet wurde und die Methode mit der gemessen wurde.

    @EaranMaleasi ja da hast du Recht, dadurch lassen sich natürlich komplexere Optimierungen vornehmen, ich würde mir trotzdem die Möglichkeit wünschen ein paar Dinge auch für JIT zur Compilezeit zu machen, wenigstens im Release build, denn da ists mir egal wenn er mal 10 mal so lange zum compilen braucht.
    Ich wollte auch mal ne total überflüssige Signatur:
    ---Leer---
    @RodFromGermany habe den Code mal angehängt im ersten post...
    Wie gesagt alle nicht steinigen ist noch Prototyp nur würde ich gerne wissen ob ich die schleifen weglassen kann.
    (oder was auch immer für verbesserungen nun aufkommen bin für alles offen)
    aber meiner meinung nach kann ich die schleifen nicht umgehen wenn ich wirklich die neuen vids haben möchte von allen usern.

    hier nochmal den code im Spoiler:
    Spoiler anzeigen

    C#-Quellcode

    1. object[] codeString = { "JSON.stringify(window.initials)" };
    2. foreach (string username in lb_users.Items)
    3. {
    4. int curPos = lb_users.Items.IndexOf(username) + 1;
    5. lbl_currentuser.Text = string.Format("Aktuell: {0} | {1} / {2} ", username, curPos, lb_users.Items.Count);
    6. int tmpN = 1;
    7. int vids = 0;
    8. int sites = 0;
    9. string URL = string.Format("https://BEISPIEL.DE/users/{0}/videos", username);
    10. webBrowser1.Navigate(URL); /// VON HIER BIS UNTEN ist natürlich unnötig und kann ich mit
    11. // webrequests natürlich viel besser machen was auch noch kommt.
    12. //Das ganze Webbrowser dingen ändert sich halt noch in webrequests.
    13. while (webBrowser1.ReadyState != WebBrowserReadyState.Complete)
    14. {
    15. Application.DoEvents(); // Darüber brauchen wir nicht reden wie gesagt das ändert sich noch in WebRequests.
    16. }
    17. if (webBrowser1.DocumentText.Contains("This profile is visible to friends only"))
    18. { //Hier ist klar... wenn das profil nur für freunde sichtbar ist kann ich nichts sehen also nächster user:
    19. lb_vidlist.Items.Add(string.Format("Profile: {0} is private", username));
    20. continue;
    21. }
    22. if (!webBrowser1.Url.ToString().Contains("videos"))
    23. { //Hier wird geprüft ob die URL noch den string "videos" enthält wenn nicht wurde weitergeleitet und man
    24. //kann die videos nicht einsehen also auch nicht verwertbar
    25. lb_vidlist.Items.Add(string.Format("Profile: {0} videos not there ^.^ ", username));
    26. continue;
    27. }
    28. var json = webBrowser1.Document.InvokeScript("eval", codeString); //hiermit bekomme ich den JSON-String.
    29. var obj = JsonConvert.DeserializeObject<uservideos.RootObject>((string)json); //sollte klar sein
    30. sites = obj.maxVideoPages; //Viele seiten an videos hat der user.
    31. //// Wenn user schon in datenbank dann weiter sonst eintragen
    32. m_dbConnection = new SQLiteConnection("Data Source=db.db;Version=3;");
    33. m_dbConnection.Open();
    34. SQLiteCommand cmd = new SQLiteCommand(m_dbConnection);
    35. cmd.CommandText = string.Format("SELECT count(*) FROM user WHERE profile_id={0}", obj.profileID);
    36. int count = Convert.ToInt32(cmd.ExecuteScalar());
    37. if (count == 0)
    38. {
    39. cmd.CommandText = string.Format("INSERT INTO user(profile_id,n_vids) VALUES ({0},{1})", obj.profileID, obj.profile._counts.video);
    40. cmd.ExecuteNonQuery();
    41. }
    42. //// Wenn user schon in datenbank dann weiter sonst eintragen ENDE
    43. SQLiteCommand cmdvid = new SQLiteCommand(m_dbConnection);
    44. while (tmpN < sites+1) //so oft durchlaufen wie seiten mit videos da sind.
    45. {
    46. bool skip = false;
    47. lbl_currentVidSite.Text = string.Format("{0} / {1}", tmpN, sites);
    48. //MessageBox.Show(tmpN.ToString());
    49. string vURL = string.Format("https://BEISPIEL.DE/users/{0}/videos/{1}", username, tmpN);
    50. webBrowser1.Navigate(vURL); //immer noch wird noch umgebaut <3
    51. while (webBrowser1.ReadyState != WebBrowserReadyState.Complete)
    52. {
    53. Application.DoEvents(); //brauch man nicht drüber reden...
    54. }
    55. var vjson = webBrowser1.Document.InvokeScript("eval", codeString); //hier wieder das gleiche... bekomme damit den JSON-String
    56. var vobj = JsonConvert.DeserializeObject<uservideos.RootObject>((string)vjson);
    57. foreach (uservideos.UserVideoCollection vid in vobj.userVideoCollection)
    58. {
    59. cmdvid.CommandText = string.Format("SELECT count(*) FROM vids WHERE vid_id={0}", vid.id);
    60. //Wenn das video schon vorhanden ist dann SKIP (also das PRoblem worum es im Thread geht.
    61. int vcount = Convert.ToInt32(cmdvid.ExecuteScalar());
    62. if (vcount == 0)
    63. {
    64. //ansonsten in die Datenbank aufnehmen
    65. cmdvid.CommandText = string.Format("INSERT INTO vids(vid_id,profile_id,vid_name) VALUES ({0},{1}, @p1)", vid.id, obj.profileID);
    66. cmdvid.Parameters.Add(new SQLiteParameter("@p1", vid.title));
    67. cmdvid.ExecuteNonQuery();
    68. string tName = String.Format("Username: {0} / Title: {1}", username, vid.title);
    69. lb_vidlist.Items.Add(tName);
    70. //und dann ein datei erstellen für jdownloader somit wird das dann runtergeladen.
    71. StreamWriter writer = new StreamWriter(vid.id + ".crawljob", false);
    72. writer.WriteLine("#" + vid.id);
    73. writer.WriteLine("text=" + vid.pageURL);
    74. writer.WriteLine("enabled=true");
    75. writer.WriteLine("autoStart=TRUE");
    76. writer.WriteLine("extractAfterDownload=TRUE");
    77. writer.WriteLine("autoConfirm=TRUE");
    78. writer.Close();
    79. writer.Dispose();
    80. string pathto = @"F:\Tools\JDownloader\folderwatch";
    81. string filename = vid.id + ".crawljob";
    82. File.Move(filename, Path.Combine(pathto, filename));
    83. vids += 1;
    84. } else
    85. { //Hier der skip
    86. skip = true;
    87. break;
    88. }
    89. }
    90. tmpN += 1;
    91. if (skip == true) {
    92. lb_vidlist.Items.Add(string.Format("SKIPPING USER: {0}", username));
    93. break; }
    94. }
    95. m_dbConnection.Close();
    96. //MessageBox.Show(vids.ToString());
    97. }
    Grüße , xChRoNiKx

    Nützliche Links:
    Visual Studio Empfohlene Einstellungen | Try-Catch heißes Eisen
    Du solltest das einfach in unterschiedliche Methoden aufteilen, außerdem macht es find ich wenig Sinn, sobald bereits ein Video des Users in der DB ist aufzuhören, was ist wenn er ein neues hat, möchtest du das dann nicht hinzufügen?
    Und ich würde mich auch erstmal um das WebBrowser gedöns kümmern.
    Wenn du das beides gemacht hast, solltest du das mit den verschachtelten schleifen gelöst haben(wenn du herausfindest wie die Methode aussehen muss).
    Ich wollte auch mal ne total überflüssige Signatur:
    ---Leer---

    xChRoNiKx schrieb:

    C#-Quellcode

    1. if (vcount == 0)
    Dreh hier die Logik um (==> != 0), da hast Du ein sehr kurzes if und das else kannst Du weglassen (nicht aber den Inhalt des Blockes), da dann im if-Zweig die Schleife verlassen wird.

    C#-Quellcode

    1. if (skip == true)
    machst Du einfach if (skip)
    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!

    jvbsl schrieb:

    1.) Du solltest das einfach in unterschiedliche Methoden aufteilen,
    2.) außerdem macht es find ich wenig Sinn, sobald bereits ein Video des Users in der DB ist aufzuhören, was ist wenn er ein neues hat, möchtest du das dann nicht hinzufügen?.

    zu 1.) daran hatte ich auch schon gedacht arbeite heute wieder ein wenig dran mal schauen was sich ergibt.
    zu 2.) Genau das passiert ja. Der JSON String hat in der VideoCollection immer das aktuellste Video an erster Stelle. Wenn also das erste Video schon vorhanden ist brauch ich die anderen ja nicht prüfen.
    Bzw sobald halt eines schon vorhanden ist kann ich abbrechen da alle dahinter ja schon in der DB sind.

    jvbsl schrieb:

    Und ich würde mich auch erstmal um das WebBrowser gedöns kümmern.

    Jup das passiert heute ;)

    @RodFromGermany: danke stimmt werd ich so umsetzen.
    Grüße , xChRoNiKx

    Nützliche Links:
    Visual Studio Empfohlene Einstellungen | Try-Catch heißes Eisen

    ErfinderDesRades schrieb:

    Aber leider ein Zusatz ohne zusätzliche Information/Argumentation. Dass man gut verständlichen und wartbaren Code schreiben soll, ist ja längst Konsens.

    Dass man keine Goto's mehr verwendet auch.

    jvbsl schrieb:

    Jeder LinQ Code lässt sich anders und performanter programmieren

    Man kann auch alles in Assembly programmieren. Da kann man noch bessere Optimierungen vornehmen.

    jvbsl schrieb:

    Und für die Behauptung du hast den Unterschied getestet und LinQ war schneller @BiedermannS hätte ich gerne den Code von beiden getesteten Varianten, die Daten mit denen getestet wurde und die Methode mit der gemessen wurde.


    Gemessen hab ich mit der Stopwatch, getestet mit folgendem Code:
    Spoiler anzeigen

    C#-Quellcode

    1. class UserVideo
    2. {
    3. public DateTime DueDate { get; set; }
    4. public string Name { get; set; }
    5. public bool Equals(UserVideo other)
    6. {
    7. return Name == other.Name && DueDate == other.DueDate;
    8. }
    9. };
    10. class DueResult
    11. {
    12. int Userid;
    13. UserVideo Video;
    14. public DueResult(int userid, UserVideo video)
    15. {
    16. Userid = userid;
    17. Video = video;
    18. }
    19. public bool Equals(DueResult other)
    20. {
    21. return Userid == other.Userid && Video.Equals(other.Video);
    22. }
    23. }
    24. static IEnumerable<DueResult> getWithLinq(int[] userids, Dictionary<int, List<UserVideo>> uservideos)
    25. {
    26. var usersWithVideos =
    27. from id in userids where uservideos.ContainsKey(id) select id;
    28. var dueVideos =
    29. from user in usersWithVideos
    30. from video in uservideos[user]
    31. where video.DueDate <= DateTime.Now
    32. select new DueResult(user, video);
    33. return dueVideos;
    34. }
    35. static IEnumerable<DueResult> getWithLoop(int[] userids, Dictionary<int, List<UserVideo>> uservideos)
    36. {
    37. var result = new List<DueResult>();
    38. foreach (var user in userids)
    39. {
    40. if (uservideos.ContainsKey(user))
    41. {
    42. foreach (var video in uservideos[user])
    43. {
    44. if (video.DueDate <= DateTime.Now)
    45. {
    46. result.Add(new DueResult(user, video));
    47. }
    48. }
    49. }
    50. }
    51. return result;
    52. }
    53. static void Main(string[] args)
    54. {
    55. int[] userids = Enumerable.Range(60, 100).ToArray();
    56. var uservideos = new Dictionary<int, List<UserVideo>>();
    57. foreach (var i in Enumerable.Range(1, 1000000))
    58. {
    59. var videoList = new List<UserVideo>{
    60. new UserVideo {
    61. Name = String.Format("SomeVideo{0}", i), DueDate = new DateTime(2017, 8, 5)
    62. },
    63. new UserVideo {
    64. Name = "SomeOtherVideo", DueDate = new DateTime(2018, 3, 6)
    65. }
    66. };
    67. uservideos.Add(i, videoList);
    68. };
    69. var sw1 = System.Diagnostics.Stopwatch.StartNew();
    70. var x = getWithLoop(userids, uservideos);
    71. sw1.Stop();
    72. Console.WriteLine("Loop: {0} ms", sw1.ElapsedMilliseconds);
    73. var sw2 = System.Diagnostics.Stopwatch.StartNew();
    74. var y = getWithLinq(userids, uservideos);
    75. sw2.Stop();
    76. Console.WriteLine("LINQ: {0} ms", sw2.ElapsedMilliseconds);
    77. var same = x.All(a => y.Any(b => a.Equals(b)));
    78. Console.WriteLine("same: {0}", same);
    79. Console.ReadLine();
    80. }




    @xChRoNiKx
    Hier mal die Linq Version. Ist zwar auch noch nicht perfekt, aber man sieht zumindest wie ichs meine.
    Zuerst wird deklarativ beschrieben welche Daten benötigt werden.
    Die TakeWhile Methode kümmert sich darum dass die Seiten nur solange heruntergeladen werden, bis eines der Videos in der DB gefunden wurde.

    Danach kannst du in der foreach mit den Daten machen was du willst und bekommst immer nur die Videos die nicht in der DB sind.

    Spoiler anzeigen

    C#-Quellcode

    1. using System;
    2. using System.Collections.Generic;
    3. using System.Linq;
    4. namespace downloader
    5. {
    6. class Program
    7. {
    8. const string HOST = "https://BEISPIEL.DE";
    9. const string USER_PAGE_FORMAT = "https://BEISPIEL.DE/{0}/videos";
    10. const string USER_VIDOES_PAGE_FORMAT = HOST + "/{0}/videos/{1}";
    11. class User
    12. {
    13. public string Name;
    14. public List<int> PageNumbers;
    15. }
    16. class UserVideoCollection
    17. {
    18. public string Username;
    19. public IEnumerable<string> Videos;
    20. }
    21. static string DownloadPage(Uri url)
    22. {
    23. throw new NotImplementedException();
    24. }
    25. static List<string> ParseUsers(string src)
    26. {
    27. throw new NotImplementedException();
    28. }
    29. static List<int> ParsePageNumbers(string src)
    30. {
    31. throw new NotImplementedException();
    32. }
    33. static List<string> ParsePage(string src)
    34. {
    35. throw new NotImplementedException();
    36. }
    37. static bool DatatbaseContainsEntry(string entry)
    38. {
    39. throw new NotImplementedException();
    40. }
    41. static void Main(string[] args)
    42. {
    43. var user_list = new List<string>
    44. {
    45. "user1"
    46. };
    47. // declare what data you want
    48. var users = from username in user_list // create User objects from user list
    49. select new User
    50. {
    51. Name = username,
    52. PageNumbers = ParsePageNumbers(DownloadPage(new Uri(String.Format(USER_PAGE_FORMAT, username))))
    53. };
    54. var video_collections = from user in users
    55. select new UserVideoCollection
    56. {
    57. Username = user.Name,
    58. Videos = from pageNumber in user.PageNumbers
    59. from video in ParsePage(DownloadPage(new Uri(String.Format(USER_VIDOES_PAGE_FORMAT, user.Name, pageNumber))))
    60. select video
    61. };
    62. // use the data
    63. foreach (var video_collection in video_collections)
    64. {
    65. Console.WriteLine("User: {0}", video_collection.Username);
    66. foreach (var video in video_collection.Videos.TakeWhile(v => !DatatbaseContainsEntry(v)))
    67. {
    68. Console.WriteLine(video);
    69. }
    70. }
    71. Console.ReadLine();
    72. }
    73. }
    74. }
    SWYgeW91IGNhbiByZWFkIHRoaXMsIHlvdSdyZSBhIGdlZWsgOkQ=

    Weil einfach, einfach zu einfach ist! :D

    BiedermannS schrieb:

    Dass man keine Goto's mehr verwendet auch.

    Konsens ist, dass man in den meisten fällen kein goto verwendet, das gilt aber nicht allgemein:
    c-faq.com/style/stylewars.html

    BiedermannS schrieb:

    Man kann auch alles in Assembly programmieren. Da kann man noch bessere Optimierungen vornehmen.

    Du hast die Behauptung aufgestellt, dass LinQ performanter sei, nicht ich. Und ja ich hatte in C# schon Gründe LinQ aus eben diesen Gründen nicht zu verwenden. Ja es ging dabei zwar um Grafikprogrammierung, da bei sowas der GC ganz böse ist. Aber es ist ein Grund.

    BiedermannS schrieb:


    Gemessen hab ich mit der Stopwatch, getestet mit folgendem Code:

    Auch Sinnvoll wäre es den Aufruf selbst mehrmals durchzuführen.

    C#-Quellcode

    1. var y = getWithLinq(userids, uservideos).ToArray();

    Ich denke sonst ist das Ergebnis nicht ganz fair, da wenn ich das richtig gesehen habe der LinQ teil erst in Zeile 92 evaluated wird. Du hast es selbst gesagt Lazy-Eval.
    Ich wollte auch mal ne total überflüssige Signatur:
    ---Leer---