Entwickler-Ecke
Basistechnologien - Implizite Verweiskonvertierung nicht vorhanden
erfahrener Neuling - Di 16.10.18 20:20
Titel: Implizite Verweiskonvertierung nicht vorhanden
Hallo Leute,
Folgendes:
Ich hatte angefangen, mir Erweiterungsmethoden für Collections aller Art zu schreiben. Bei genauer Angabe des Typs (z. B. ControlColllection) funktioniert das auch ganz gut.
Jetzt wollte ich das aber verallgemeinern, z. B. so
C#-Quelltext
1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11: 12: 13: 14: 15: 16: 17: 18:
| public static int RemoveWhere<T1, T2>(this T1 collection, Func<T2, bool> condition) where T1 : ICollection<T2> { int removeCount = 0; foreach (T2 obj in collection) if (condition.Invoke(obj)) { collection.Remove(obj); removeCount++; } return removeCount; }
bzw. so public static int RemoveWhere<T1>(this T1 collection, Func<object, bool> condition) where T1 : ICollection<object> { ... } |
Die Einschränkung auf
ICollection ist notwendig, damit meine collection die Methode Remove kennt (und das die Methode nur bei Listen, Collection, etc. auftaucht).
Nun erhalte ich beim Aufruf der Methode aber den Compilerfehler
CS0311 [
https://docs.microsoft.com/de-de/dotnet/csharp/language-reference/compiler-messages/cs0311]
Hat jemand eine Idee, was ich machen muss, damit es nach diesem Schema funktioniert?
Oder macht man das vielleicht prinzipiell anders?
MfG
Julian
Ralf Jansen - Di 16.10.18 20:57
DataGridViewRowCollection ist keine IList<T> sondern nur eine IList (nicht generisch). Insofern kann man das nicht einfach casten. Linq bringt aber schon eine ExtensionMethod mit die aus einer IList eine IList<T> macht. Die Cast<T> Methode.
Du müßtest also auf deiner DataGridViewRowCollection einmal Cast<DataGridViewRow>() aufrufen. Dadurch bekommst du nebenbei auch eine neue Liste. Was hier den Vorteil hat das dein Code auch funktioniert könnte wenn man das an der richtigen Stelle tut ;) Du versuchst in einem foreach die Liste zu ändern über die du gerade iterierst. Das ist nicht erlaubt und sollte zur Laufzeit knallen.
Edit: Ich korrigiere Cast erzeugt noch keine neue List sondern nutzt denn originalen Enumerator wird also auch knallen. Du mußt auch einmal ToList() aufrufen um eine neue Liste zu erzeugen.
erfahrener Neuling - Di 16.10.18 21:27
Ralf Jansen hat folgendes geschrieben : |
Du versuchst in einem foreach die Liste zu ändern über die du gerade iterierst. Das ist nicht erlaubt und sollte zur Laufzeit knallen. |
Also wenn ich die Methode so aufrufe:
C#-Quelltext
1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11:
| public static int RemoveWhere(this DataGridViewRowCollection rowCollection, Func<DataGridViewRow, bool> condition) { int removeCount = 0; foreach (DataGridViewRow row in rowCollection) if (condition.Invoke(row)) { rowCollection.Remove(row); removeCount++; } return removeCount; } |
dann gibt es keinen Laufzeitfehler und die korrekten Rows werden entfernt.
Ralf Jansen hat folgendes geschrieben : |
Du mußt auch einmal ToList() aufrufen um eine neue Liste zu erzeugen. |
Wo genau meinst du? DataGridViewRowCollection oder ControlCollection kennen bei mir kein
ToList() oder andere Linq-Methoden
EDIT:
Achso vorher noch den Cast ausführen
also:
dataGridViewData.Rows.Cast<DataGridViewRow>().ToList()...
EDIT 2:
Also ich seh schon, dass das hier glaub ich zu nichts führt. Eine neue Liste zu bearbeiten bringt mich nicht weiter, sondern macht es nur komplizierter. Dann muss ich eben für jeden Typen eine eigene Methode schreiben (siehe oben).
Trotzdem danke!
Ralf Jansen - Di 16.10.18 21:54
Zitat: |
dann gibt es keinen Laufzeitfehler und die korrekten Rows werden entfernt. |
Das ist ein Nebeneffekt der konkreten DataGridViewRowCollection Implementierung. Dort entspricht Remove eher einem verstecken. Da wird also nicht wirklich gelöscht womit dann foreach kein Problem hat. Im allgemeinen Fall wird es aber knallen und du versuchst ja eine allgemeine Lösung zu schaffen. Ist da ein wenig unglücklich das DataGridViewRowCollection schon eine sehr ~spezielles~ Konstrukt ist, sich explizit anders verhält und du das als Bespiel Collection benutzt.
Zitat: |
DataGridViewRowCollection oder ControlCollection kennen bei mir kein ToList() oder andere Linq-Methoden |
Weil, wie schon gesagt, DataGridViewRowCollection nicht auf generischen Klassen aufbaut. Und Linq basiert nun mal stark auf Generics. DataGridViewRowCollection gehört zu Winforms und ist damit älter als Generics und kommt ohne aus. Microsoft hat es nie für nötig gehalten das zu aktualisieren womit sich in der Winforms Welt Linq und Konsorten oft genug ein Fremdkörper ist. Die dachten damals schon, so ungefähr 2005, das Winforms alter Quatsch ist.
Zitat: |
Eine neue Liste zu bearbeiten bringt mich nicht weiter, sondern macht es nur komplizierter. |
Das war nicht das wo ich dich hinführen wollte. Eine neue Liste solltest du nur zum iterieren benutzen. Löschen solltest du die in der Original Liste. Auch wenn das 2 Listen sind die Objekte darin sind ja trotzdem die gleichen.
Ein simples
C#-Quelltext
1: 2: 3:
| foreach (var row in rowCollection.ToList()) if (condition.Invoke(row)) rowCollection.Remove(row); |
würde schon reichen. Deiner Feststellung das das nichts bringt würde ich aber in teilen teilen ;) Mindestens für DataGridViewRowCollection brauchst du bestimmt ein spezielle Lösung. Eine allgemeine Lösung die auch für DataGridViewRowCollection funktioniert wird hässlich.
erfahrener Neuling - Di 16.10.18 22:12
Ralf Jansen hat folgendes geschrieben : |
Eine neue Liste solltest du nur zum iterieren benutzen. Löschen solltest du die in der Original Liste. |
Ok jetzt hab ich's auch verstanden. Das behebt den Laufzeitfehler. Dann habe ich zwar trotzdem noch das Problem, das ich im Methodenkopf auf
IList<T2> oder
ICollection<T2> einschränken müsste (damit er
Remove() kennt) und somit die ganze Sache nur für richtige Listen interessant wird, aber trotzdem danke für den Tipp :zustimm:
Thema erledigt!
Entwickler-Ecke.de based on phpBB
Copyright 2002 - 2011 by Tino Teuber, Copyright 2011 - 2024 by Christian Stelzmann Alle Rechte vorbehalten.
Alle Beiträge stammen von dritten Personen und dürfen geltendes Recht nicht verletzen.
Entwickler-Ecke und die zugehörigen Webseiten distanzieren sich ausdrücklich von Fremdinhalten jeglicher Art!