Entwickler-Ecke
Basistechnologien - Custom-Generic.List.Sort<>()
VampireSilence - So 26.06.11 19:17
Titel: Custom-Generic.List.Sort<>()
Also ich habe mir mit den Custom Generics eine eigene FileCollection erstellt und möchte die nun nach Datum sortieren. Die zugehörige Klasse sieht folgendermaßen aus:
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: 30: 31: 32: 33: 34: 35: 36: 37: 38: 39: 40: 41: 42: 43: 44: 45: 46: 47: 48: 49: 50: 51: 52: 53:
| public class FileCollection<T> : IEnumerable<T> { private List<T> arFiles = new List<T>();
public T Get(int pos) { return arFiles[pos]; }
public void Add(T c) { arFiles.Add(c); }
public void Sort() { arFiles.Sort(); }
public void Sort(bool Descending) { arFiles.Sort(new FileCollectionItemComparer(Descending)); }
public void Clear() { arFiles.Clear(); }
public int Count { get { return arFiles.Count; } }
IEnumerator<T> IEnumerable<T>.GetEnumerator() { return arFiles.GetEnumerator(); }
System.Collections.IEnumerator IEnumerable.GetEnumerator() { return arFiles.GetEnumerator(); }
private class FileCollectionItemComparer : IComparer<T> { private bool _Descending = false;
public FileCollectionItemComparer(bool Descending) { this._Descending = Descending; }
public int Compare(FileCollectionItem x, FileCollectionItem y) { if (_Descending) { return (int)y.LastFileAccess.Subtract(x.LastFileAccess).TotalSeconds; } else { return (int)x.LastFileAccess.Subtract(y.LastFileAccess).TotalSeconds; } }
public int Compare(T x, T y) { return 0; } } } |
Das Ganze habe ich initialisiert mit:
C#-Quelltext
1:
| FileCollection<FileCollectionItem> _FileList = new FileCollection<FileCollectionItem>(); |
Und das FileCollectionItem habe ich folgendermaßen aufgebaut:
C#-Quelltext
1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11: 12: 13: 14: 15:
| struct FileCollectionItem { public string Name, Fullpath, Extension; public DateTime LastFileAccess;
public FileCollectionItem(string Path, DateTime LastFileAccess) { string[] parts = Path.Split(new string[] { "\\", "." }, StringSplitOptions.RemoveEmptyEntries);
this.Fullpath = Path; this.Extension = "." + parts[parts.Length - 1]; this.Name = parts[parts.Length - 2] + this.Extension; this.LastFileAccess = LastFileAccess; } } |
So. Und wenn ich jetzt aber _FileList.Sort(); oder _FileList.Sort(true); ausführe, passiert überhaupt garnichts. Wäre super, wenn ihr mir da ein bisschen auf die Sprünge helfen könntet.
mfg
- VampireSilence
Christian S. - So 26.06.11 19:35
Hallo!
Was mir erstmal auffällt: Bei Sort übergibst Du keinen Comparer.
Und dann stellt sich mir doch irgendwie die Frage, wozu Du eine eigene Klasse baust, wenn Du doch wieder nur die Methoden der List<T> benutzt.
Und was sind Custom Generics? Ich kenne nur "normale" Generics und was anderes benutzt Du auch nicht ;-)
Grüße
Christian
P.S.: Ich finde Comparison<T> ja weniger sperrig zu implementieren als IComparer<T>.
VampireSilence - So 26.06.11 19:46
Also ich habe 2 mal Sort(), einmal mit und einmal ohne Comparer. Im Programm benutze ich aber meistens dieser Version:
C#-Quelltext
1: 2:
| public void Sort(bool Descending) { arFiles.Sort(new FileCollectionItemComparer(Descending)); } |
Da brauche ich keinen Comparer übergeben, weil der in der Methode erst erstellt wird.
Die Methoden, der List<T> benutze ich, weils im Tutorial so da stand, ich keine Alternative kenne und bisher auch funktioniert hat. ^^
Naja und Custom ist es, weil ich keine bereits vorhandere nehme, wie StringCollection, sondern eine eigene erstelle. Custom halt. Wie Custom Contents bei PS3 Games. :P
mfg
- VampireSilence
Kha - So 26.06.11 20:13
Dass bei Sort() nichts passiert, kaufe ich dir nicht ab:
Zitat: |
InvalidOperationException
The default comparer Comparer<T>.Default cannot find an implementation of the IComparable<T> generic interface or the IComparable interface for type T. |
Bei deinem Comparer hast du dich mit den Generics ein wenig verzettelt. Sort ruft auf ihm IComparer<T>.Compare auf, was ja bei dir immer 0 zurückgibt ;) . Du hast da noch eine andere Methode drin, aber die hat durch ihre Parameter keine Beziehung zum Interface, wird also nie aufgerufen.
Die Lösung: Lass das T komplett weg. Wenn deine FileCollection FileCollectionItems enthalten soll, sag das auch so:
C#-Quelltext
1: 2: 3: 4:
| public class FileCollection : IEnumerable<FileCollectionItem> { ... private class FileCollectionItemComparer : IComparer<FileCollectionItem> |
In allen anderen Punkten schließe ich mich Christian an :) . Und wo bei StringCollection Generics vorhanden sind, habe ich auch noch nicht herausbekommen :zwinker: .
VampireSilence - So 26.06.11 20:30
Ja, die Methode mit dem return 0; musste ich hinzufügen, weil der Compiler unbedingt eine Variante mit T haben wollte und T nunmal kein LastFileAccess besitzt. Da T einem FileCollectionItem entspricht, müsste doch aber auch die entsprechende Methode gewählt werden oder nicht ? Ich kann new string() doch schließlich auch einmal mit char* und einmal mit sbyte* aufrufen, woraufhin die jeweils zutreffende Variante gewählt wird ?
Naja ich hab T jetzt jedenfalls überall durch FileCollectionItem ersetzt und nun steht in der Zeile:
C#-Quelltext
1:
| return (int)y.LastFileAccess.Subtract(x.LastFileAccess).TotalSeconds; |
hier folgendes:
C#-Quelltext
1:
| "FileCollectionItem" enthält keine Definition für "LastFileAccess", und es konnte keine Erweiterungsmethode "LastFileAccess" gefunden werden, die ein erstes Argument vom Typ "FileCollectionItem" akzeptiert. |
Und das obwohl nur ein paar Zeilen darunter LastFileAccess definitiv als public Datetime definiert ist UND obwohl es vorher mit T nie Probleme an dieser Stelle gab. Das verwirrt mich. -.-
Der Vollständigkeithalber hier nochmal der komplette Code:
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: 30: 31: 32: 33: 34: 35: 36: 37: 38: 39: 40: 41: 42: 43: 44: 45: 46: 47: 48: 49: 50: 51: 52: 53: 54: 55: 56: 57: 58: 59: 60: 61: 62: 63: 64: 65: 66: 67: 68: 69: 70:
| public class FileCollection<FileCollectionItem> : IEnumerable<FileCollectionItem> { private List<FileCollectionItem> arFiles = new List<FileCollectionItem>();
public FileCollectionItem Get(int pos) { return arFiles[pos]; }
public void Add(FileCollectionItem c) { arFiles.Add(c); }
public void Sort() { arFiles.Sort(); }
public void Sort(bool Descending) { arFiles.Sort(new FileCollectionItemComparer(Descending)); }
public void Clear() { arFiles.Clear(); }
public int Count { get { return arFiles.Count; } }
IEnumerator<FileCollectionItem> IEnumerable<FileCollectionItem>.GetEnumerator() { return arFiles.GetEnumerator(); }
System.Collections.IEnumerator IEnumerable.GetEnumerator() { return arFiles.GetEnumerator(); }
private class FileCollectionItemComparer : IComparer<FileCollectionItem> { private bool _Descending = false; public FileCollectionItemComparer(bool Descending) { this._Descending = Descending; }
public int Compare(FileCollectionItem x, FileCollectionItem y) { if (_Descending) { return (int)y.LastFileAccess.Subtract(x.LastFileAccess).TotalSeconds; } else { return (int)x.LastFileAccess.Subtract(y.LastFileAccess).TotalSeconds; } }
public int Compare(T x, T y) { return 0; } }
}
struct FileCollectionItem { public string Name, Fullpath, Extension; public DateTime LastFileAccess;
public FileCollectionItem(string Path, DateTime LastFileAccess) { string[] parts = Path.Split(new string[] { "\\", "." }, StringSplitOptions.RemoveEmptyEntries);
this.Fullpath = Path; this.Extension = "." + parts[parts.Length - 1]; this.Name = parts[parts.Length - 2] + this.Extension; this.LastFileAccess = LastFileAccess; } } |
mfg
- VampireSilence
Kha - So 26.06.11 20:37
Schau dir meinen Code bitte noch einmal an... du hast gerade einen Typparameter namens FileCollectionItem eingeführt :mrgreen: .
VampireSilence hat folgendes geschrieben : |
Da T einem FileCollectionItem entspricht |
Das tut es, wenn du
IComparer<FileCollectionItem> schreibst, aber ansonsten ist T ungebunden.
VampireSilence - Mo 27.06.11 00:38
Ähm, ja.. merke: Suchen&Alles ersetzen ist nicht immer dein Freund. ^^
Habs entfernt und nun gehts. Aber warum der IComparer im Einzelfall nicht die richtige Compare()-Variante wählt, ist mir immernoch schleierhaft.
Aber Danke für die Hilfe! :)
mfg
- VampireSilence
Entwickler-Ecke.de based on phpBB
Copyright 2002 - 2011 by Tino Teuber, Copyright 2011 - 2025 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!