Überladenes Equals wird nicht aufgerufen

jokey2

Erfahrenes Mitglied
Hallo Gemeinde!

Ich versuche mich gerade an C# und bin da auf ein Problem gestoßen:
Ich habe eine Klasse erstellt, die 3 string-Datenmember enthält. Elemente dieses Klassentyps speichere ich in einer ArrayList. In der Klasse habe ich die Equals-Methode überschrieben:
Code:
        public override bool Equals(object obj)
        {
            return
            (
                (obj == this) ||
                (
                    (obj.GetType() == this.GetType()) &&
                    (m_strName.Equals((obj as CSyncOrder).Name))
                ) ||
                (
                    (obj.GetType() == typeof(string)) &&
                    (m_strName.Equals(obj as string))
                )
            );
        }
Nun möchte ich ein Element in der ArrayList finden, indem ich die Methode IndexOf() verwende. Laut MSDN verwendet diese Methode die Equals-Methode zum Vergleich.
Leider wird meine überladene Equals-Methode nicht aufgerufen und das entsprechende Objekt nicht gefunden.
Kann mir jemand sagen, was ich da falsch mache?

Code:
        private ArrayList m_SyncOrders = new ArrayList();
...

        private void listViewSyncOrders_ItemCheck(object sender, System.Windows.Forms.ItemCheckEventArgs e)
        {
            int iItemIndex = e.Index;
            ListViewItem itemSO = listViewSyncOrders.Items[iItemIndex];
            string strName = itemSO.SubItems[0].Text;
            int iArrayIndex = m_SyncOrders.IndexOf(strName); //<-- Hier wird nichts gefunden
            if(iArrayIndex < 0)
                return;
            CSyncOrder ClickedSyncOrder = (CSyncOrder)m_SyncOrders[iArrayIndex];
            ClickedSyncOrder.Active = System.Convert.ToBoolean(e.NewValue);
        }
Die zu suchenden Elemente sind in der Liste vorhanden. Die Equals-Methode wird nicht aufgerufen.

Für sachkundige Hilfe bin ich wie immer dankbar!

[VS.NET 2003; C#]
 
es gibt die Schnittstelle IEquable<T> (oder so änhlich).
glaube die musst du noch implementieren.
 
So heißt es:

System.IEquatable(Of T)

Verwendet dann folgendermaßen:

Code:
Class Test
    Implements IEquatable(Of ...)

    Public Function Equals1(ByVal other As ...) As Boolean Implements System.IEquatable(Of ...).Equals

    End Function
End Class
 
Erstmal vielen Dank für die Antworten. Leider haben sie mir nicht weitergeholfen. Die Schnittstelle IEquatable gibt es erst ab .NET 2.0. Ich programmiere unter VS.NET 2003 mit .NET 1.1.
Ich hänge hier mal eine Testapplikation an. Vielleicht kann mir ja dann jemand sagen, was ich da falsch mache. Ich habe meine Klasse noch mit der Schnittstelle IComparable versehen, das hat aber auch nichts geändert.

ClassMain.cs
Code:
using System;
using System.Collections;

namespace ArrayListTestApp
{
    /// <summary>
    /// Zusammenfassung für ClassMain.
    /// </summary>
    class ClassMain
    {
        /// <summary>
        /// Der Haupteinstiegspunkt für die Anwendung.
        /// </summary>
        [STAThread]
        static void Main(string[] args)
        {
            ArrayListTest ALT = new ArrayListTest();
            
            //Ausgabe
            ALT.OutputElement();
        }


    }

    public class ArrayListTest
    {
        public ArrayList m_listSyncOrders = new ArrayList();

        public ArrayListTest()
        {
            //Elemente in die Liste
            AddElements();
        }

        void AddElements()
        {
            CSyncOrder NewSyncOrder = new CSyncOrder("Eins", "Dir1_1", "Dir1_2");
            m_listSyncOrders.Add(NewSyncOrder);

            NewSyncOrder = new CSyncOrder("Zwei", "Dir2_1", "Dir2_2");
            m_listSyncOrders.Add(NewSyncOrder);

            NewSyncOrder = new CSyncOrder("Drei", "Dir3_1", "Dir3_2");
            m_listSyncOrders.Add(NewSyncOrder);
        }

        public void OutputElement()
        {
            int iArrayIndex = m_listSyncOrders.IndexOf("Zwei");

            if(iArrayIndex >= 0)
            {
                CSyncOrder FoundSO = m_listSyncOrders[iArrayIndex] as CSyncOrder;
                System.Console.WriteLine("Name: " + FoundSO.Name + "; Dir1: " + FoundSO.Dir1 + "; Dir2: " + FoundSO.Dir2);
            }
        }
    }

    public class CSyncOrder : IComparable
    {
        protected string m_strName;
        protected string m_strDir1;
        protected string m_strDir2;
        protected bool m_bActive = true;

        public CSyncOrder(string strName)
        {
            m_strName = strName;
        }

        public CSyncOrder(string strName, string strDir1, string strDir2)
        {
            m_strName = strName;
            m_strDir1 = strDir1;
            m_strDir2 = strDir2;
        }

        public override bool Equals(Object obj)
        {
            if (obj == null)
                return false;
            
            CSyncOrder SO = obj as CSyncOrder;
            
            if ((System.Object)SO == null)
                return false;

            return (m_strName == SO.Name);
        }

        public bool Equals(CSyncOrder SO)
        {
            if (SO == null)
                return false;

            return (m_strName == SO.Name);
        }

        public bool Equals(string Name)
        {
            if (Name == null)
                return false;

            return (m_strName == Name);
        }

        public override int GetHashCode()
        {
            return m_strName.GetHashCode();
        }

        public string Name
        {
            get{return m_strName;}
            set{m_strName = value;}
        }

        public string Dir1
        {
            get{return m_strDir1;}
            set{m_strDir1 = value;}
        }

        public string Dir2
        {
            get{return m_strDir2;}
            set{m_strDir2 = value;}
        }

        public bool Active
        {
            get{return m_bActive;}
            set{m_bActive = value;}
        }

        public int CompareTo(object obj)
        {
            if(obj is CSyncOrder) 
            {
                CSyncOrder SO = (CSyncOrder) obj;

                return m_strName.CompareTo(SO.m_strName);
            }
        
            throw new ArgumentException("object is not a CSyncOrder");    
        }
    }
}
Ich habe es mit Breakpoints getestet, keine der Equals-Funktionen wird aufgerufen.
Ich wäre sehr dankbar, wenn mir jemand weiterhelfen könnte. Es muß ja eine Möglichkeit geben, in einer Liste nach einem Element zu suchen.
Es wäre natürlich besser, eine typisierte Liste zu verwenden, die scheint es aber in .NET1.1 noch nicht zu geben :suspekt:.
 
Gibt es denn einen triftigen Grund, nicht auf .NET 2.0 oder sogar 3.5 umzusteigen? Die Entwicklungsumgebungen sind ja durch die Express Versionen kostenlos erhältlich.
 
Ich möchte eigentlich nicht das Projekt auf eine neuere Version migrieren, da das erfahrungsgemäß mehr Probleme bringt als es löst. Es muß ja unter .NET 1.1 auch irgendwie möglich sein, oder?
 
Ich habe mir gerade mal dein Beispiel in der Entwicklungsumgebung angeschaut (VS2005). Die Methode Equals(object) ruft er auf.

Mir kommt die Logik des dort durchgeführten Vergleichs recht fragwürdig vor, da du offensichtlich versuchst, hier einen String mit dem Wert "Zwei" über den as-operator nach CSyncOrder zu casten.
Da dies nicht möglich ist, liefert Equals(object) immer false.

Ich vermute das Problem liegt in der IndexOf-Methode selbst, da diese nicht Equals(string) aufruft. Vielleicht solltest du einfach in der Equals(object) Methode prüfen ob obj ein String ist und entsprechend reagieren.
 
Ich habe mir gerade mal dein Beispiel in der Entwicklungsumgebung angeschaut (VS2005). Die Methode Equals(object) ruft er auf.
Dann scheint es da einen Unterschied zu VS.NET 2003 zu geben. Denn bei mir wird die Methode definitiv nicht aufgerufen. Ich habe einen Breakpoint an den Methodenbeginn gesetzt und dort wird nicht angehalten.
Mir kommt die Logik des dort durchgeführten Vergleichs recht fragwürdig vor, da du offensichtlich versuchst, hier einen String mit dem Wert "Zwei" über den as-operator nach CSyncOrder zu casten.
Da dies nicht möglich ist, liefert Equals(object) immer false.
Daraus schließe ich, daß bei Dir die Equals(Object obj)-Methode aufgerufen wird. Ich ging davon aus, daß wenn eine Equals-Methode mit einem string-Parameter aufgerufen wird, dann automatisch die Equals(string Name)-Methode aufgerufen wird, da sie ja vorhanden ist.

Es scheint mir so, daß das in dieser .NET-Version alles noch nicht so recht funktioniert.:confused:
 
ArrayList hält als Typ immer Object daher wird auch die Equals Methode für Object aufgerufen. Andernfalls müsste die ArrayList intern ja selbst nach String casten, was aber nicht gegeben ist.
 
Es hätte ja sein können, daß implizit die passende Equals-Methode aufgerufen würde. Die Typinformation ist ja im Objekt vorhanden. Hab' ich wohl zuviel erwartet. :rolleyes:

Ich habe mir mal testweise VS 2008 Express runtergeladen und installiert. Tatsächlich wird dort der Code ohne Änderungen korrekt ausgeführt, d.h. Equals(object) wird aufgerufen. Nachdem ich in diese Equals-Methode auch noch eine Typerkennung für string-Objekte eingefügt habe, funktioniert das so, wie ich es will.

Da ist wohl ein dicker BUG in VS.NET 2003. Und das in der Professional-Version! :(
[Weitere Kommentare runtergeschluckt]

Danke für Eure Hilfe.
 

Neue Beiträge

Zurück