| Autor |
Beitrag |
Ccenter
      
Beiträge: 154
Win7
C#
|
Verfasst: Sa 27.11.10 23:00
Nabend,
ich versuche gerade, ganz simpel, einen String von einem anderen zu subtrahieren.
Normalerweise hätte ich das mit Replace gemacht, allerdings funktioniert es in diesem Fall nicht.
Ich bastel gerade am folgenden Projekt:
Mein Programm läuft per Notifyicon im Systemtray und soll, sobald ein neuer Prozess gestartet wird, per ShowBalloonTip den neuen Prozess anzeigen. Das soll einem mehr Sicherheit über die gestarteten Anwendungen/Prozesse geben.
Um den Namen des Prozess auszugeben, soll das Programm zuerst einen String mit aktuellen Prozessen anlegen. Dannach wird per Schleife immer wieder eine neue Prozessliste erstellt und verglichen. Die alte Prozessliste wird dann immer aktualisiert. Das subtrahieren funktioniert aber nicht.
Lässt sich ein so großer String mir replace nicht ersetzen?
newList = newList.Replace(oldProcessList, "");
|
|
Luckie
Ehemaliges Mitglied
Erhaltene Danke: 1
|
Verfasst: Sa 27.11.10 23:02
Leere doch die Liste vorher.
|
|
Ccenter 
      
Beiträge: 154
Win7
C#
|
Verfasst: Sa 27.11.10 23:37
Wird sie. Ist Replace die beste Wahl dafür?
|
|
Luckie
Ehemaliges Mitglied
Erhaltene Danke: 1
|
Verfasst: Sa 27.11.10 23:52
Überlege doch mal, was Replace macht. Wie wäre es mit Clear oder wie auch immer die Methode heißt.
|
|
Kha
      
Beiträge: 3803
Erhaltene Danke: 176
Arch Linux
Python, C, C++ (vim)
|
Verfasst: So 28.11.10 11:55
Ccenter hat folgendes geschrieben : | | Um den Namen des Prozess auszugeben, soll das Programm zuerst einen String mit aktuellen Prozessen anlegen. |
Einen String? Aufzählbare Informationen speichert man normalerweise in einer Liste, hier wohl noch besser ein HashSet... und die lassen sich auch problemlos subtrahieren  .
_________________ >λ=
|
|
Ccenter 
      
Beiträge: 154
Win7
C#
|
Verfasst: So 28.11.10 16:10
Mit Replace kann ich innerhalb eines Strings einen Teil von diesem durch einen anderen ersetzen. Wenn ich also einen String habe den ich gerne subtrahieren möchte, muss ich als neuen String eingendlich nur "" angeben. Das funktioniert auch, solange der zu ersetzende string in meinem Fall nur aus ein paar Zeichen bestand.
Diesen großen String will er aber irgendwie nicht ersetzen.
C#-Quelltext 1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11: 12: 13: 14: 15: 16: 17: 18: 19: 20: 21: 22: 23: 24: 25: 26: 27:
| private void backgroundWorker1_DoWork(object sender, DoWorkEventArgs e) { string startList = ""; foreach (Process p in Process.GetProcesses()) startList += p.ProcessName;
while (true) { string newList = ""; foreach (Process p2 in Process.GetProcesses()) newList += p2.ProcessName;
if (startList != newList) { string startListcopyed = startList; startList = newList;
notifyIcon1.ShowBalloonTip(2, "Neuer Prozess", newList, ToolTipIcon.Info); } } } |
Ist "Hashset" in diesem Fall wirklich nötig? Ich finde da irgendwie keine schlüssige Erklärung zu. Das muss doch irgendwie auf Array/Stringbasis machbar sein.
|
|
Kha
      
Beiträge: 3803
Erhaltene Danke: 176
Arch Linux
Python, C, C++ (vim)
|
Verfasst: So 28.11.10 18:34
Ccenter hat folgendes geschrieben : | | Diesen großen String will er aber irgendwie nicht ersetzen. |
Dann hast du die Funktionsweise von Replace noch nicht verstanden, denn die Methode weiß eben nicht, dass du hier einen String als Listen-Ersatz missbrauchen willst. In dem String "a b c d" kommt "a c" nicht vor, also wird Replace auch nichts ersetzen.
Wenn dir der Mengenbegrifff aus der Mathematik bekannt ist, sollte dir auch die Funktionsweise eines HashSets bekannt sein, aber wie wäre es damit:
Am Anfang füllst du eine List<string> mit GetProcesses. In der inneren foreach-Schleife schaust du dann nach, ob p2 bereits in der Liste vorhanden ist. Wenn ja, einfach ignorieren, ansonsten sowohl an die Liste als auch an eine String-Variable anfügen, die du dann nach der Schleife im Balloon-Tip anzeigst.
_________________ >λ=
|
|
Ccenter 
      
Beiträge: 154
Win7
C#
|
Verfasst: Di 30.11.10 19:44
Ok, nur folgendes Problem:
Mit Replace habe ich eine wesentlich kürzere Liste erhalten, obwohl teilweise immer noch Prozesse angezeigt wurden, die eigendlich nicht hätten drinne sein dürfen.
Wenn ich jetzt p2 an die Lsite anhänge, bekomme ich ja eine super lange Liste. Wie soll ich denn nun den einen Prozess rausfiltern, der neu ist?
C#-Quelltext 1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11: 12: 13: 14: 15: 16: 17: 18: 19: 20: 21: 22: 23: 24: 25: 26: 27: 28: 29:
| private void backgroundWorker1_DoWork(object sender,DoWorkEventArgs e) { string startList = "";
List<string> lines = new List<string>(); foreach (Process p in Process.GetProcesses()) lines.Add(p.ProcessName);
while (true) { string newList = ""; foreach (Process p2 in Process.GetProcesses()) newList += p2.ProcessName;
if (!(lines.Contains(newList))) { lines.Add(newList); }
} } |
|
|
Trashkid2000
      
Beiträge: 561
Erhaltene Danke: 137
|
Verfasst: Di 30.11.10 21:13
Hallo,
also ich würde es so machen: Initial erstmal alle Prozesse abfragen:
C#-Quelltext 1:
| Process[] currentProcesses = Process.GetProcesses(); |
Im Eventhandler des Backgroundworkers würde ich dann immer wieder(also in einer Endlosschleife) die Prozesse, die gerade laufen, immer wieder abfragen, und die beiden Arrays miteinander vergleichen. Nachdem diese verglichen sind, würde ich dann currentProcesses durch das Array der Prozesse im Moment immer wieder überschreiben. Denn es macht ja keinen Sinn, Prozesse, die beendet wurden, immer noch in der Liste zu führen. Oder  Mit der Endlosschleife musst Du auch mal schauen, ob Du da noch ein Thread.Sleep einbaust, also, in welchen Abständen die Prozesse abgefragt werden sollen.
C#-Quelltext 1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11: 12: 13: 14: 15: 16: 17: 18: 19: 20: 21: 22: 23: 24:
| private void worker_DoWork(object sender, DoWorkEventArgs e) { while (true) { Process[] processesNow = Process.GetProcesses(); if (currentProcesses != null) { IEnumerable<Process> newProcesses = processesNow.Where(p1 => currentProcesses.Where(p2 => p2.Id == p1.Id) .Count() < 1); IEnumerable<Process> exitedProcesses = currentProcesses.Where(p1 => processesNow.Where(p2 => p2.Id == p1.Id) .Count() < 1);
foreach (Process newProcess in newProcesses) { Console.WriteLine(string.Format("Neuer Prozess: {0}", newProcess.ProcessName)); } foreach (Process exitedProcess in exitedProcesses) { Console.WriteLine(string.Format("Beendeter Prozess: {0}", exitedProcess.ProcessName)); } } currentProcesses = processesNow; } } |
Hoffe, der Code versteht sich ein bisschen.
LG,
Marko
//edit: Klammer im Code war verschwunden
Zuletzt bearbeitet von Trashkid2000 am Di 30.11.10 22:48, insgesamt 1-mal bearbeitet
|
|
Ccenter 
      
Beiträge: 154
Win7
C#
|
Verfasst: Di 30.11.10 22:32
Vom Prinzip her sollte das Programm genau das machen, was du beschrieben hast. Nur das subtrahieren der Listen hat eben nicht funktioniert.
Vielen Dank für die Hilfe, hat mir mal wieder mein Problem gelöst
Allerdings habe ich gerade Probleme mit dem Verständniss von:
IEnumerable<Process> newProcesses = processesNow.Where(p1 => currentProcesses.Where(p2 => p2.Id == p1.Id).Count() < 1);
Ich bin mit msdn gerade überfordert, wäre schön wenn mir jemand die gesammte Zeile erklären könnte.
So wie ich das verstehe: Ich deklariere ein IEnumerable(Es ist eine Aufzählung aber wo ist der Unterschied zu z.B. List?) vom Typ Process. Hinterher Möchte ich daraus den Namen des neuen Prozess erhalten. Aber wie? was macht "processesNow.Where(p1 => currentProcesses.Where(p2 => p2.Id == p1.Id).Count() < 1);" ?
Insbesondere mit p2 => p2.Id == p1.Id).Count() < 1 kann ich gerade kaum was anfangen. Also wie gesagt, wäre nett wenn jemand das erklären könnte =)
mfg Ccenter
|
|
Trashkid2000
      
Beiträge: 561
Erhaltene Danke: 137
|
Verfasst: Mi 01.12.10 08:15
Hallo,
stimmt wohl, habe zwar eine Lösung gepostet, aber eigentlich garnicht Deine Frage beachtet bzw. beantwortet...
Denke mal, dass Problem war einfach mal folgendes:
C#-Quelltext 1: 2: 3: 4: 5: 6: 7: 8: 9: 10:
| while (true) { string newList = ""; foreach (Process p2 in Process.GetProcesses()) newList += p2.ProcessName; if (!(lines.Contains(newList))) { lines.Add(newList); } } | Also, lines ist eine List<string>, in der initial die Namen der Prozesse, die beim Starten des Backgroundworkers laufen, reingeschrieben werden. Warum eigentlich keine List<Process>? Dadurch gehen Dir doch Informationen verloren, wenn Du nur noch einen Namen eines Prozesses hast. Aber andere Sache.
So, in der while-Schleife fragst Du also immer wieder die Prozesse ab und schreibst alle Prozessnamen aneinandergereiht in newList. Wenn es schon "newList" heißt, warum dann nicht wirklich eine List<string>?
So, Du hast also einen ziemlich langen string, und prüfst dann, ob dieser in lines enthalten ist. Wie sollte er, wenn doch in lines die Prozessnamen einzeln drin stehen.
Wenn, dann müsstest Du das Add vielleicht auch in der foreach machen
C#-Quelltext 1: 2: 3: 4: 5: 6: 7: 8:
| foreach (Process p2 in Process.GetProcesses()) { if (!(lines.Contains(p2.ProcessName))) { lines.Add(p2.ProcessName); } } | Aber das Problem hierbei ist: Ich kann ein Programm mehrmals starten (also neuer Process). Es hat aber immer den gleichen Namen, wodurch es schon in der Liste steht und dann nicht erkannt wird. Und auf der anderen Seite kann ich ein Programm zwischendurch beenden, und dann wieder neu starten (neuer Process). Da Du in der Liste aber immer nur hinzufügst, wird dieser Fall auch nicht erkannt. Eindeutig (jedenfalls für die Laufzeit einer Sitzung) ist da nur die Id des Processes.
Die Erklärung zu dem von mir geposteten Code mit den beiden LinQ-Abfragen kommt noch. Aber ich muss nun zur Arbeit. Oder jemand anderes hier wäre so nett, das mal kurz zu erklären!
LG, Marko
|
|
|