none
Objekte vergleichen RRS feed

  • Frage

  • Hallo Gemeinde,

     

    ich habe mehrere Instanzen ein und derselben Klasse.

    die teilweise dadurch entstanden das man sie clonete. 

    Nun sind sie aber bearbeitet worden, teilweise nur geringfügig. Ich möchte nun wissen, wie kann ich , im ersten Schritt, herausbekommen ob Werte geändert wurden?

    Im Step 2 möchte ich die Änderungen ermitteln, natürlich sollte dies möglichst schnell geschehen.

     

    Gibt es hierzu bessere Methoden als durch die Propertys zu iterieren?

     

     

    Danke

     

     

     

    Mittwoch, 25. Januar 2012 08:36

Antworten

  • Hallo,

    Auf deine Frage gibt es keine eindeutige Antwort, da wir gar nichts von der Klasse wissen, die du instanziiert hast und die Du nun mit einer geklonten Instanz vergleichen möchtest. Wir wissen auch nicht, ob die geänderten Werte, die Du feststellen möchtest, nur Werte sind, die über öffentliche Member erreichbar sind, oder auch interne Werte (Zustand).

    Darüber hinaus gibt es unterschiedliche Levels von Klonen: die flache Member-Kopie, bei der nur die Property-Werte auf eine neue Instanz übertragen werden (wie wir sie meist in IClonable-Implementationen finden) und es gibt noch die tiefe Kopie, die oft über binäre Serialisierung in ein MemoryStream erreicht wird.

    Und es gibt die unterschiedlichsten Vergleichs-Arten. Und unterschiedliche Überschreibung von Object.Equals: Typen wie String oder Integer überschreiben die geerbte Methode und stellen fest, ob die Werte identisch sind, während die Basisimplementation ein simpler Verweisvergleich ist, der angibt, ob die Referenzen auf das gleiche Objekt verweisen.

    Person x = new Person();
    Person y = new Person();
    Console.WriteLine(x.Equals(y)); // immer falsch (falls Equals nicht überschrieben wurde), da versch. Objekte

    Egal ob Du im obigen Beispiel die gleichen Property-Werte einsetzt, die Objekte bleiben verschieden.

    Wenn es sich um eine eigene Klasse handelt, die Du beliebig verändern kannst, könntest Du einen schnellen binären Vergleich der Instanzen vornehmen, z.B.:

    [Serializable]
    class Person : ICloneable, IComparable<Person>, IEquatable<Person>
    {
        public string FirstName { get; set; }
        public string LastName { get; set; }
    
        public object Clone() {
            return new Person { FirstName = FirstName, LastName = LastName };
        }
    
        public int CompareTo(Person y)
        {
            BinaryFormatter formatter = new BinaryFormatter();
    
            using (MemoryStream memoryStreamX = new MemoryStream())
            {
                using (MemoryStream memoryStreamY = new MemoryStream())
                {
                    formatter.Serialize(memoryStreamX, this);
                    formatter.Serialize(memoryStreamY, y);
    
                    var binaryArrayX = memoryStreamX.GetBuffer();
                    var binaryArrayY = memoryStreamY.GetBuffer();
    
                    if (binaryArrayX.Length != binaryArrayY.Length)
                        return binaryArrayX.Length.CompareTo(binaryArrayY.Length);
    
                    for (int i = 0; i < binaryArrayX.Length; i++)
                        if (binaryArrayX[i] != binaryArrayY[i])
                            return binaryArrayX[i].CompareTo(binaryArrayY[i]);
                }
            }
    
            return 0;
        }
    
        public bool Equals(Person other) {
            return (this.CompareTo(other) == 0);
        }
    
        public override bool Equals(object obj) {
            return (this.CompareTo((Person)obj) == 0);
        }
    
        public override int GetHashCode() {
            return base.GetHashCode();
        }
    
        public static bool operator==(Person x, Person y) {
            return x.Equals(y);
        }
    
        public static bool operator !=(Person x, Person y) {
            return !x.Equals(y);
        }
    }
    
    

     

    Jetzt kannst Du den ersten Codeauschnitt nochmals testen:

    Person x = new Person();
    Person y = new Person();
    Console.WriteLine(x.Equals(y)); // immer wahr da zwar versch. Objekte, aber Wertegleichheit

    So könnte man auf die Schnelle sagen, ob zwei Objekte wertegleich sind (bitgleich, vereinfacht).

    Es gibt aber auch intelligentere Verfahren, z.B. die Implementierung von INotifyPropertyChanged, IEditableObject und der IChangeTracking-Schnittstelle. So könntest Du in jedem Property-Setter automatisch IChangeTracking.IsChanged auf true setzen und nicht nur immer passiv wissen, ob sich dein Objekt geändert hat, sondern auch von diesem über die INotifyPropertyChanged-Schnittstelle erfahren, sobald eine Änderung eingetreten ist.

    Gruß
    Marce

    Mittwoch, 25. Januar 2012 11:06
    Moderator
  • Hi,

    dafür gibt es bspw. das hier:

      http://msdn.microsoft.com/de-de/library/bsc2ak47.aspx

    Da wird IMHO gut erklärt, wie man mit Equals arbeitet und eine Vergleichsmethoden aufbauen kann.

     


    Gruß, Stefan
    Microsoft MVP - Visual Developer ASP/ASP.NET
    http://www.asp-solutions.de/ - Consulting, Development
    http://www.aspnetzone.de/ - ASP.NET Zone, die ASP.NET Community
    Mittwoch, 25. Januar 2012 09:05
    Moderator

Alle Antworten

  • Hi,

    dafür gibt es bspw. das hier:

      http://msdn.microsoft.com/de-de/library/bsc2ak47.aspx

    Da wird IMHO gut erklärt, wie man mit Equals arbeitet und eine Vergleichsmethoden aufbauen kann.

     


    Gruß, Stefan
    Microsoft MVP - Visual Developer ASP/ASP.NET
    http://www.asp-solutions.de/ - Consulting, Development
    http://www.aspnetzone.de/ - ASP.NET Zone, die ASP.NET Community
    Mittwoch, 25. Januar 2012 09:05
    Moderator
  • Hallo,

    Auf deine Frage gibt es keine eindeutige Antwort, da wir gar nichts von der Klasse wissen, die du instanziiert hast und die Du nun mit einer geklonten Instanz vergleichen möchtest. Wir wissen auch nicht, ob die geänderten Werte, die Du feststellen möchtest, nur Werte sind, die über öffentliche Member erreichbar sind, oder auch interne Werte (Zustand).

    Darüber hinaus gibt es unterschiedliche Levels von Klonen: die flache Member-Kopie, bei der nur die Property-Werte auf eine neue Instanz übertragen werden (wie wir sie meist in IClonable-Implementationen finden) und es gibt noch die tiefe Kopie, die oft über binäre Serialisierung in ein MemoryStream erreicht wird.

    Und es gibt die unterschiedlichsten Vergleichs-Arten. Und unterschiedliche Überschreibung von Object.Equals: Typen wie String oder Integer überschreiben die geerbte Methode und stellen fest, ob die Werte identisch sind, während die Basisimplementation ein simpler Verweisvergleich ist, der angibt, ob die Referenzen auf das gleiche Objekt verweisen.

    Person x = new Person();
    Person y = new Person();
    Console.WriteLine(x.Equals(y)); // immer falsch (falls Equals nicht überschrieben wurde), da versch. Objekte

    Egal ob Du im obigen Beispiel die gleichen Property-Werte einsetzt, die Objekte bleiben verschieden.

    Wenn es sich um eine eigene Klasse handelt, die Du beliebig verändern kannst, könntest Du einen schnellen binären Vergleich der Instanzen vornehmen, z.B.:

    [Serializable]
    class Person : ICloneable, IComparable<Person>, IEquatable<Person>
    {
        public string FirstName { get; set; }
        public string LastName { get; set; }
    
        public object Clone() {
            return new Person { FirstName = FirstName, LastName = LastName };
        }
    
        public int CompareTo(Person y)
        {
            BinaryFormatter formatter = new BinaryFormatter();
    
            using (MemoryStream memoryStreamX = new MemoryStream())
            {
                using (MemoryStream memoryStreamY = new MemoryStream())
                {
                    formatter.Serialize(memoryStreamX, this);
                    formatter.Serialize(memoryStreamY, y);
    
                    var binaryArrayX = memoryStreamX.GetBuffer();
                    var binaryArrayY = memoryStreamY.GetBuffer();
    
                    if (binaryArrayX.Length != binaryArrayY.Length)
                        return binaryArrayX.Length.CompareTo(binaryArrayY.Length);
    
                    for (int i = 0; i < binaryArrayX.Length; i++)
                        if (binaryArrayX[i] != binaryArrayY[i])
                            return binaryArrayX[i].CompareTo(binaryArrayY[i]);
                }
            }
    
            return 0;
        }
    
        public bool Equals(Person other) {
            return (this.CompareTo(other) == 0);
        }
    
        public override bool Equals(object obj) {
            return (this.CompareTo((Person)obj) == 0);
        }
    
        public override int GetHashCode() {
            return base.GetHashCode();
        }
    
        public static bool operator==(Person x, Person y) {
            return x.Equals(y);
        }
    
        public static bool operator !=(Person x, Person y) {
            return !x.Equals(y);
        }
    }
    
    

     

    Jetzt kannst Du den ersten Codeauschnitt nochmals testen:

    Person x = new Person();
    Person y = new Person();
    Console.WriteLine(x.Equals(y)); // immer wahr da zwar versch. Objekte, aber Wertegleichheit

    So könnte man auf die Schnelle sagen, ob zwei Objekte wertegleich sind (bitgleich, vereinfacht).

    Es gibt aber auch intelligentere Verfahren, z.B. die Implementierung von INotifyPropertyChanged, IEditableObject und der IChangeTracking-Schnittstelle. So könntest Du in jedem Property-Setter automatisch IChangeTracking.IsChanged auf true setzen und nicht nur immer passiv wissen, ob sich dein Objekt geändert hat, sondern auch von diesem über die INotifyPropertyChanged-Schnittstelle erfahren, sobald eine Änderung eingetreten ist.

    Gruß
    Marce

    Mittwoch, 25. Januar 2012 11:06
    Moderator
  • Hallo umocomp1,

    Ich gehe davon aus, dass die Antworten Dir weitergeholfen haben.
    Solltest Du noch "Rückfragen" dazu haben, so gib uns bitte Bescheid.

    Grüße,
    Robert


    Robert Breitenhofer, MICROSOFT  Twitter Facebook
    Bitte haben Sie Verständnis dafür, dass im Rahmen dieses Forums, welches auf dem Community-Prinzip „Entwickler helfen Entwickler“ beruht, kein technischer Support geleistet werden kann oder sonst welche garantierten Maßnahmen seitens Microsoft zugesichert werden können.

    Montag, 13. Februar 2012 10:38
    Moderator