Laden...

Generischer Vergleich 2er Objekte

Erstellt von elTorito vor 8 Jahren Letzter Beitrag vor 8 Jahren 2.300 Views
elTorito Themenstarter:in
177 Beiträge seit 2009
vor 8 Jahren
Generischer Vergleich 2er Objekte

Hi,

ich habe eine SortableBindingList<T> namens "Projects", wo ich die Stelle suchen möchte an der ein Objekt eingefügt werden soll:


public int BinarySearch(T item, IComparer<T> comparer)
        {
            List<T> itemsList = (List<T>)this.Items;
            return itemsList.BinarySearch(item, comparer);
        }


Project item = getProjectItem(index);

CompareProject dc = new CompareProject();
int searchIndex = Projects.BinarySearch(item, dc);
Projects.Insert(~searchIndex, item);

Ich benutze ein Comparer (hier abgeguckt)


public class CompareProject : IComparer<Project>
    {
        public int Compare(Project p1, Project p2)
        {
            int result;
            if (Project.ReferenceEquals(p1, p2))
            {
                result = 0;
            }
            else
            {
                if (p1 == null)
                {
                    result = 1;
                }
                else if (p2 == null)
                {
                    result = -1;
                }
                else
                {
                    result = StringCompare(p1.ProjectName, p2.ProjectName);
                    if (result == 0)
                    {
                         result = StringCompare(p1.ProjectName, p2.ProjectName);
                    }
                }
            }
            return result;

        }

        int StringCompare(string strFirstString, string secondString)
        {

            int result;

            if (strFirstString == null)
            {

                if (secondString == null)
                {

                    result = 0;

                }

                else
                {

                    result = 1;

                }

            }

            else
            {

                result = strFirstString.CompareTo(secondString);

            }

            return result;

        }
    }

Wie bekomme ich das Generisch, so dass ich 2 x beliebige Objekte vergleichen kann?
Spätestens nach


public class CompareObject<T> : IComparer<T>
    {
        public int Compare(T p1, T p2)
        {
...

viel mir ein das ich ja gar nicht auf p1.ProjectName zugreifen kann, ich müsste also den zu vergleichenden String schon mit übergeben?

Ich wollte mal versuchen mit:


public class CompareObject<T> : IComparer<T>
    {
        private Comparison<T> comparison;

        public CompareObject(Comparison<T> comparison)
        {
            if (comparison == null)
                throw new ArgumentNullException("comparison");
            
            this.comparison = comparison;
        }

 public int Compare(T o1, T o2)
        {
            return comparison(o1, o2);
        }

IComparer<Project> objectComparer = new CompareObject<Project>((x, y) => x.ProjectName.CompareTo(y.ProjectName));


Da aber wird gemoppert das IComparer<Project> nicht nach Icomparer<object> konvertiert werden kann.

Müsste ich dann casten?


IComparer<Project> objectComparer = new CompareObject<Project>((x, y) => x.ProjectName.CompareTo(y.ProjectName));
int searchIndex = Objects.BinarySearch(item, (IComparer<object>)objectComparer);

Kann man das so machen? Oder wie würde man so eine Comparer Methode schreiben, damit man X Beliebige Objekte vergleichen kann?

Danke

Gruß
Peter

5.657 Beiträge seit 2006
vor 8 Jahren

Hi elTorito,

hätte es wirklich soo viel Text und Code für diese eine Frage gebraucht?

wie würde man so eine Comparer Methode schreiben, damit man X Beliebige Objekte vergleichen kann?

Wenn man eine Compare-Methode für jeden beliebigen Typen implementieren könnte, wäre das sicherlich bereits im Framework enthalten. Die IComparer<T>.Compare-Methode kannst du jeweils nur für einen Typ implementieren. Das kann aber auch eine Überklasse sein, von der du andere Klassen abgeleitet hast. Zum Einschränken der Typen kannst du die where-Einschränkung verwenden.

Christian

Weeks of programming can save you hours of planning

elTorito Themenstarter:in
177 Beiträge seit 2009
vor 8 Jahren

Hi Mr Sparkle,

hätte es wirklich soo viel Text und Code für diese eine Frage gebraucht?
wie würde man so eine Comparer Methode schreiben, damit man X Beliebige Objekte vergleichen kann?

Jein, die andere Frage war ja noch ob man es so machen könnte:

IComparer<Project> objectComparer = new CompareObject<Project>((x, y) => x.ProjectName.CompareTo(y.ProjectName));
int searchIndex = Objects.BinarySearch(item, (IComparer<object>)objectComparer);

Hab dein Link mal gelesen, aber verstehe dass nicht so wirklich, zudem bin ich noch auf den Blog hier gestoßen, wo BinarySearch erweitert wird...

Und nun zu dem Entschluss gekommen dass es wohl die falsche herangehensweise für mein Vorhaben ist. Ich Glaube, ich verkomplizier es mal wieder.

Ich hab ein DataGridView, durch drücken der Taste F3 wird eine neue Zeile eingefügt an der Stelle wo man sich gerade befindet, nach Eingabe eines Wertes, und verlassen der Zelle, soll die darunterliegende Liste sich neu sortieren und der Cursor zu der neu eingefügten Zeile wechseln.

Ich hatte BinarySearch dafür benutzt um Objekte zu vergleichen, und die tatsächliche einzufügende Position in meiner Liste zu ermitteln, und anschließend zu dieser Position zu springen. Esrt danach hatte ich neu sortiert.

Habe das nun anders gelöst, ich füge das Objekt an der Position ein wo ich gerade stehe, dann sortiere ich die Liste, hole mir die Position vom neuen Objekt und springe dahin... Ist wahrscheinlich auch weniger fehleranfällig 😃

Danke

S
248 Beiträge seit 2008
vor 8 Jahren

Hallo elTorito,

ich würde Project das Interface IComparable<Project> implementieren lassen (Implementierung deines Comparers).
Danach kannst du aus


public int BinarySearch(T item, IComparer<T> comparer)
        {
            List<T> itemsList = (List<T>)this.Items;
            return itemsList.BinarySearch(item, comparer);
        }


public int BinarySearch(T item)
        {
            List<T> itemsList = (List<T>)this.Items;
            return itemsList.BinarySearch(item);
        }

machen und es sollte automatisch deine Implementierung für die binäre Suche verwendet werden.
Ich hoffe das ist was du suchst.

Grüße
spooky

5.657 Beiträge seit 2006
vor 8 Jahren

Hi elTorito,

Hab dein Link mal gelesen, aber verstehe dass nicht so wirklich

...was aber kein Grund sein sollte, sich nicht trotzdem mal mit Generics auseinanderzusetzen. Das gehört halt einfach zu den Grundlagen, mit denen man als C#-Entwickler arbeitet.

Ansonsten scheint mir dein Ansatz tatsächlich unnötig kompliziert zu sein. Unter WPF könnte man deine Anforderungen allein mit MVVM bzw. Databinding lösen. Unter WinForms gibt es sicherlich auch eine bessere Möglichkeit. Kompliziert wird die Sache bei dir, da du auf eine Trennung der Schichten verzichtest. Daher mal als Lesetip der Hinweis auf [Artikel] Drei-Schichten-Architektur.

Christian

Weeks of programming can save you hours of planning

elTorito Themenstarter:in
177 Beiträge seit 2009
vor 8 Jahren

Kompliziert wird die Sache bei dir, da du auf eine Trennung der Schichten verzichtest. Daher mal als Lesetip der Hinweis auf [Artikel] Drei-Schichten-Architektur.

...was aber kein Grund sein sollte, sich nicht trotzdem mal mit Generics auseinanderzusetzen. Das gehört halt einfach zu den Grundlagen, mit denen man als C#-Entwickler arbeitet.

Hi,

ja, ich versuche mich grad mit Generics auseinander zu setzen. Ich habe mich da ein bisschen verzettelt glaube ich.

Mein Ziel ist es ein Formular zu haben mit ein DGV, welches an einer Sortierbaren BindingList gebunden ist, die sortierbar sein soll, diese Liste kann mal Auto, Flugzeug, Person, Project sein...

Ich möchte dann nur das jeweilige Object angeben, und so für alle Objekte die gleichen Sortier, hinzufüge usw Funktionen benutzen. Da komme ich um Generics ja gar nicht herum.

Und dabei stellte sich das Problem das die diversen Objekte jeweils nach einer anderen Spalte (eigenschaft) sortiert werden könnten, und ich dann versuchte diese Angabe irgendwie mitzugeben, und habe mich dabei verzettelt ...

5.657 Beiträge seit 2006
vor 8 Jahren

Und dabei stellte sich das Problem das die diversen Objekte jeweils nach einer anderen Spalte (eigenschaft) sortiert werden könnten

Dann ist doch das DGV für die Sortierung verantwortlich. Du meinst doch die Sortierfunktion, wenn man auf den Spaltennamen im Header klickt? Dann mußt du das doch nicht nocheinmal neu implementieren.

Christian

Weeks of programming can save you hours of planning

elTorito Themenstarter:in
177 Beiträge seit 2009
vor 8 Jahren

Und dabei stellte sich das Problem das die diversen Objekte jeweils nach einer anderen Spalte (eigenschaft) sortiert werden könnten

Dann ist doch das DGV für die Sortierung verantwortlich. Du meinst doch die Sortierfunktion, wenn man auf den Spaltennamen im Header klickt? Dann mußt du das doch nicht nocheinmal neu implementieren.

Jein... bin jetzt verwirrt...

das DGV soll mir immer nur dazu dienen die gebundene Liste anzuzeigen. Im DGV habe ich z.B.

Apfel
Banane
Kiwi
Mango

ich stehe auf zeile Kiwi und füge eine Zeile ein , habe nun eine Leerzeile zwischen Banane und Kiwi , ich tippe Orange ein, und die Orange soll sich in der gebunden Liste hinter Mango einfügen.

Das DGV kann ja kein ListChangedEvent, es soll immer nur abbilden was gerade darunter passiert.

das DGV kann auch nicht Sortieren durch Klick auf den Spaltennamen, wenn es an einer Liste gebunden ist.

Presenting the SortableBindingList<T>