Laden...

LINQ Expression zum Sortieren von Objekten wirft Exception aus

Erstellt von TKipp vor 4 Jahren Letzter Beitrag vor 4 Jahren 1.245 Views
T
TKipp Themenstarter:in
18 Beiträge seit 2019
vor 4 Jahren
LINQ Expression zum Sortieren von Objekten wirft Exception aus

Hallo Leute,
folgender Code soll eingentlich die von einem Webservice gelieferten Objekte, die über eine Combobox ausgelesen werden, sortieren. Tut es aber nicht. Anstatt dessen bekomme ich die Exception:> Fehlermeldung:

"mindestens ein Objekt muss IComparable implementieren"

Was ist da los? Was läuft falsch? wie geht's richtig?
Hier zunächst der Code der Klasse, welches die Objekte liefert:


using System;
using System.Collections.Generic;
using System.Text;
using ControlExpert_PostMaster.PostMasterWs;

namespace ControlExpert_PostMaster
{
    /// <summary>
    /// Container class for Receiver from WSDL with overwritten ToString() method.
    /// Note: Not inherited, because then the object is not applicable to the WSDL-object without cast etc.
    /// </summary>
    public class AmsReceiver
    {
        public Receiver Receiver { get; set; }

        public override String ToString()
        {
            if (this.Receiver != null)
            {
                return Receiver.ReceiverName;
            }
            else
            {
                return null;
            }
        }
    }
}

und hier der Code, dessen LINQ statement besagte Exception auswirft:


        private void setReceivers() {
            this.cmbReceiver.SelectedIndexChanged -= this.cmbReceiver_SelectedIndexChanged;
            //TKipp/27.03.2019/Sort Receiver in alpabetical order
            List<AmsReceiver> receivers=new List<AmsReceiver>();
            if(this.transactionData.Receivers != null) {
                receivers.AddRange(this.transactionData.Receivers);
                receivers = (from item in receivers
                                               orderby item.Receiver descending
                                               select item).ToList();

                this.cmbReceiver.DataSource = receivers;
            } else
                this.cmbReceiver.DataSource = this.transactionData.Receivers;
            //TKipp/27.03.2019/End of sorting

            this.cmbReceiver.SelectedIndex = -1;
            this.cmbReceiver.SelectedIndexChanged += this.cmbReceiver_SelectedIndexChanged;
        }

Die Objekte sind lt.Debugger mittels AddRange in die Liste eingefügt worden, werden allerdings nicht sortiert, da das LINQ statement fehlerhaft ist...

TKipp

D
261 Beiträge seit 2015
vor 4 Jahren

Woher soll die Sortiermethode denn wissen, nach welcher Logik du sortieren möchtest?
Du übergibst lediglich das Property Receiver von AmsReceiver und der Typ Receiver hat anscheinend keine IComparable-Schnittstelle, somit gibt es auch keine Sortierlogik.

T
2.219 Beiträge seit 2008
vor 4 Jahren

Vermutlich wolltest du noch die Property ReceiverName bei der orderby mitgeben 😃


receivers = (from item in receivers orderby item.Receiver.ReceiverName descending select item).ToList();

Developer, Developer, Developer, Developer....

99 little bugs in the code, 99 little bugs. Take one down, patch it around, 117 little bugs in the code.

4.931 Beiträge seit 2008
vor 4 Jahren

Ist Receiver eine Klasse von dir?
Ansonsten kannst du mittels eine der List.Sort()-Methoden (ohne LINQ) das Sortieren durchführen - am einfachsten selber eine Comparison<T>-Methode erstellen, welche dann -1, 0 oder 1 zurückliefert:


int CompareReceivers(Receiver receiver1, Receiver receiver2)
{
  // compare
  return ...;
}

Und noch als Hinweis:
die ToString-Methode kannst du verkürzen zu


public override string ToString()
{
     return Receiver?.ReceiverName;
}

T
TKipp Themenstarter:in
18 Beiträge seit 2019
vor 4 Jahren

Receiver ist eine Klasse des Webservices, der mir die Objekte liefert.
Folgender Code funktioniert, d.h., er sortiert die Objekte in alphabetischer Reihenfolge ohne, wie bisher eine Exception auszuwerfen.


       private void setReceivers() {
            this.cmbReceiver.SelectedIndexChanged -= this.cmbReceiver_SelectedIndexChanged;
            //TKipp/27.03.2019/Sort Receiver in alpabetical order
            AmsReceiver ams = new AmsReceiver();
            List<AmsReceiver> receivers = new List<AmsReceiver>();
            if(this.transactionData.Receivers != null) {
                receivers.AddRange(this.transactionData.Receivers);
                receivers.Sort((item1, item2) => item1.Receiver.ReceiverName.CompareTo(item2.Receiver.ReceiverName));
                this.cmbReceiver.DataSource = receivers;
            } else
                this.cmbReceiver.DataSource = this.transactionData.Receivers;
            //TKipp/27.03.2019/End of sorting

            this.cmbReceiver.SelectedIndex = -1;
            this.cmbReceiver.SelectedIndexChanged += this.cmbReceiver_SelectedIndexChanged;
        }

Dasselbe kürzer:


 List<AmsReceiver> receivers = (from item in this.transactionData.Receivers
                                                   orderby item.Receiver.ReceiverName ascending
                                                   select item).ToList();

Danke für den Tipp, den Code verkürzen zu können. Allerdings benutze ich ternäre Operatoren nur ungerne.Ist folgender Ausdruck äquivalent zu Deinigem


return  this.Receiver==null ? null : Receiver.ReceiverName;

TKipp

4.931 Beiträge seit 2008
vor 4 Jahren

Ja, dein ToString()-Code ist (semantisch) identisch zu meinem.
Jedoch verwendest gerade du den ternären Operator ? : (denn dieser verwendet ja 3 Teilausdrücke 😉. Dafür wurde ja gerade der ?.-Operator eingeführt, um die Abfrage auf null nicht immer ausschreiben zu müssen (vermeiden sollte man aber Kaskaden von ?.-Abfragen in einem längeren geschachtelten Ausdruck).