2016-07-26 29 views
-1
aufgerufen werden

Ich versuche IEquatable zu implementieren, damit ich .Exception in meinen benutzerdefinierten Typ LINQ-Abfragen verwenden konnte.Equals, GetHashCode und Operatoren Override nicht in IEquatable-Implementierung

Der benutzerdefinierte Typ Code sieht wie folgt aus:

public class Case : IEquatable<Case> 
    { 
     [Key] 
     public int Id { get; set; } 

     //More properties 
     [...]  

     public bool Equals(Case other) 
     { 
      // Check whether the compared object references the same data. 
      if (ReferenceEquals(this, other)) return true; 

      // Check whether the compared object is null. 
      if (ReferenceEquals(other, null)) return false; 

      // Check whether the objects’ properties are equal. 
      return Id.Equals(other.Id); 
     } 

     public override bool Equals(object obj) 
     { 
      var other = obj as Case; 
      // Check whether the compared object references the same data. 
      if (ReferenceEquals(this, other)) return true; 

      // Check whether the compared object is null. 
      if (ReferenceEquals(other, null)) return false; 

      // Check whether the objects’ properties are equal. 
      return Id.Equals(other.Id); 
     } 

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

     public static bool operator ==(Case case1, Case case2) 
     { 
      if ((object)case1 == null || (object)case2 == null) 
       return Equals(case1, case2); 
      return case1.Equals(case2); 

     } 

     public static bool operator !=(Case case1, Case case2) 
     { 
      if ((object)case1 == null || (object)case2 == null) 
       return !Equals(case1, case2); 
      return !case1.Equals(case2); 
     } 
    } 

I throw new NotImplementedException(); in der Equals-Methode hinzugefügt haben, aber es wird nie aufgerufen. https://msdn.microsoft.com/en-us/library/ms131190.aspx

und hier https://blogs.msdn.microsoft.com/csharpfaq/2009/03/25/how-to-use-linq-methods-to-compare-objects-of-custom-types/

aber keinen Erfolg:

Ich habe die Konventionen, die hier gezeigt gefolgt.

EDIT

Hier ist der Code, der für die Außer-Methode aufruft:

if (Checkset(set)) 
        { 
         var subset = GetPowerSet(set); 
         var newset = powerset.Except(subset); 
        } 

Wo beide powerset und subset Array von Case.

+4

Können Sie die Linq-Code hinzufügen, wo erwartet wird, Equals anrufen? –

+0

Hat Ihr Testfall zwei 'Fälle' mit derselben 'ID'? – PetSerAl

+0

@RubenAguilar hat den Code hinzugefügt! – RainierMallol

Antwort

0

Bevor Sie versuchen, Dinge mit Ihren Linq-Abfragen zu tun, würde ich empfehlen, mit etwas einfacher zu spielen. I.E.

var case1_1 = new Case() { Id = 1 }; 
var case1_2 = new Case() { Id = 1 }; 

var areEqual = case1_1 == case1_2; 

Mit diesem Test an Ort und Stelle, das sind die Gründe, warum ich denken kann, warum Sie nicht, dass die Ausnahme getroffen haben:

  1. Sie haben 2 Equals Methoden, und Sie warf nur die Ausnahme von 1 von ihnen.
  2. Keine 2 Objekte, die Sie verglichen haben, haben die gleiche Id. Wenn das Ergebnis von GetHashCode unterschiedlich ist, versucht es möglicherweise nicht einmal , die Werte zu vergleichen.
  3. Die Ausnahme gefangen wurde
+0

Hallo, danke für deine Antwort. Ich habe mehrere Tests gemacht und: 1. Vor allem, mit 2 Equals-Methoden ist die Art und Weise, die IEqueatble implementiert werden sollte, eine überschreiben die vorherige Signatur der Klasse, und die andere Angabe eines benutzerdefinierten Vergleich mit dem Typ Case. Dies wird in der MSDN-Verknüpfung vorgeschlagen, die ich als Referenz angegeben habe. Die Ausnahme wird nie ausgelöst. 2. Ich habe auch die neue Exception werfen in den GetHashCode geworfen, die nicht ausgewertet wird. Ich weiß genau, dass die Fälle, die ich vergleiche, übereinstimmen. 3. Keine Ausnahme wurde abgefangen. – RainierMallol

+0

@RainierMallol Ich sagte nicht, dass Sie nicht 2 gleich Methoden haben sollten. Ich habe nur gesagt, dass du vielleicht die falsche eingecheckt hast. –

0

Ich würde gerne wissen, ob Sie sich für Equals in beiden Überlastungen versucht Trapping ... das einzige, was aus dem Code herausspringt, ist, dass Sie doppelte Implementierungen haben Gleichheit für die Überprüfung . Im Idealfall würden Sie das nur an einem Ort tun.

Hier ist eine Beispielimplementierung ... Sie EntityBase mit Case ...

/// <summary> 
    /// Indicates whether the current object is equal to another object of the same type. 
    /// </summary> 
    /// <returns> true if the current object is equal to the <paramref name="other" /> parameter; otherwise, false. </returns> 
    /// <param name="other"> An object to compare with this object. </param> 
    public bool Equals(EntityBase other) { 
    return !ReferenceEquals(other, null) 
      && Id.Equals(other.Id); 
    } 

    /// <summary> 
    /// Serves as a hash function for a particular type. 
    /// </summary> 
    /// <returns> A hash code for the current <see cref="T:System.Object" />. </returns> 
    /// <filterpriority> 2 </filterpriority> 
    public override int GetHashCode() { 
    return Id.GetHashCode(); 
    } 

    /// <summary> 
    /// Determines whether the specified <see cref="T:System.Object" /> is equal to the current <see cref="T:System.Object" />. 
    /// </summary> 
    /// <returns> true if the specified object is equal to the current object; otherwise, false. </returns> 
    /// <param name="obj"> The object to compare with the current object. </param> 
    /// <filterpriority> 2 </filterpriority> 
    public override bool Equals(object obj) { 
    return Equals(obj as EntityBase); 
    } 

    /// <summary> 
    /// Determines if the <paramref name="left" /> instance is considered equal to the <paramref name="right" /> object. 
    /// </summary> 
    /// <param name="left"> The instance on the left of the equality operator. </param> 
    /// <param name="right"> The instance on the right of the equality operator. </param> 
    /// <returns> True if the instances are considered equal, otherwise false. </returns> 
    public static bool operator ==(EntityBase left, EntityBase right) { 
    return ReferenceEquals(left, null) 
     ? ReferenceEquals(right, null) 
     : left.Equals(right); 
    } 

    /// <summary> 
    /// Determines if the <paramref name="left" /> instance is considered unequal to the <paramref name="right" /> object. 
    /// </summary> 
    /// <param name="left"> The instance on the left of the inequality operator. </param> 
    /// <param name="right"> The instance on the right of the inequality operator. </param> 
    /// <returns> True if the instances are considered unequal, otherwise false. </returns> 
    public static bool operator !=(EntityBase left, EntityBase right) { 
    return !(left == right); 
    } 
+0

Hallo Peter John, danke für deine Nachricht. Ihrem Code fehlt eine Implementierung von IQetable .Equals (EntityBase). Ich habe es meinem Code hinzugefügt und bekomme immer noch die gleichen Ergebnisse. – RainierMallol

0

Wenn Sie nur ersetzen würde rufen Ausnahme:

var exceptList = list1.Except(list2); 

Keine Liste zurückgegeben wird, können Sie die comparation auszuführen müssen die Ergebnisse der Ausnahme aufzählen, mit einer foreach zum Beispiel:

foreach(var listElement in exceptList) 
{ 
    //... 
} 

Dann werden die Methoden GetHashCode und Equals aufgerufen.

EDIT: Dieser Code führt eine Ausnahme von zwei Listen:

static void Main(string[] args) 
    { 
     List<MyClass> list1 = new List<MyClass>(); 

     MyClass myClass1 = new MyClass() {Id = 1}; 
     MyClass myClass2 = new MyClass() {Id = 2}; 

     list1.Add(myClass1); 
     list1.Add(myClass2); 

     List<MyClass> list2 = new List<MyClass>(); 
     list2.Add(myClass1); 

     var exceptList = list1.Except(list2); 

     foreach (var myClass in exceptList) 
     { 
      Console.WriteLine(myClass.Id); 
     } 
    } 


    public class MyClass : IEquatable<MyClass> 
    { 
     public int Id { get; set; } 

     public bool Equals(MyClass other) 
     { 
      return Id == other.Id; 
     } 

     public override int GetHashCode() 
     { 
      return Id; 
     } 
    } 

Dieser Code druckt "2" in der Konsole

+0

Hallo, was passiert ist, dass die Except-Liste überhaupt nicht funktioniert, also wäre der Wert von exceptList in diesem Fall der gleiche wie list1. – RainierMallol

+0

Ich habe einen Beispielcode zur Antwort hinzugefügt –

+0

Danke für das Posten, aber ich habe es auf diese Weise versucht und immer noch das Verhalten ist das gleiche. Ich weiß in der Tat, dass die Objekte in der Teilmenge in der alten Liste sind, da es ein Powerset eines der alten Listenobjekte ist. Ein Powerset ist ein Set, das alle möglichen Kombinationen von Elementen in einem Set enthält. Also ist die alte Menge ein vorheriges Powerset eines X-Items, und die neue Menge ist ein Powerset der alten Menge, was bedeutet, dass alle diese Items in der alten Liste sind, daher müssen sie in meiner BL gelöscht werden . – RainierMallol

0

Equals wird nur bei Bedarf aufgerufen. Alle LINQ-Methoden, die an IEquatable<T> Implementierungen arbeiten, verwenden (und speichern) zuerst die Hash-Codes der Objekte, die sie verarbeiten. Diese Methoden rufen nur Equals, wenn zwei Objekte den gleichen Hash-Code haben.

In Ihren Daten gibt es keinen Fall mit identischen Id s, so dass es nie erforderlich ist, Equals zu rufen.

Dies kann leicht anhand eines Beispiels demonstriert werden. Wenn Sie drei Listen:

var list1 = new List<Case> 
{ 
    new Case{ Id = 1 }, 
    new Case{ Id = 2 }, 
    new Case{ Id = 3 } 
}; 
var list2 = new List<Case> 
{ 
    new Case{ Id = 4 }, 
    new Case{ Id = 5 }, 
    new Case{ Id = 6 } 
}; 
var list3 = new List<Case> 
{ 
    new Case{ Id = 1 }, 
    new Case{ Id = 5 }, 
    new Case{ Id = 6 } 
}; 

Dann wird die folgende Anweisung (mit einigen Trace-Anweisungen in Equals und GetHashCode, und diese einfach Rückkehr Id) ...

list1.Except(list2).ToList(); 

... AUSGABE:

GetHashCode: 4 
GetHashCode: 5 
GetHashCode: 6 
GetHashCode: 1 
GetHashCode: 2 
GetHashCode: 3 

Während der Aussage ...

list1.Except(list3).ToList(); 

... AUSGABE:

GetHashCode: 1 
GetHashCode: 5 
GetHashCode: 6 
GetHashCode: 1 
Equals: 1 - 1 
GetHashCode: 2 
GetHashCode: 3 
+0

Vielen Dank, aber die GetHashCode-Methode wird auch nie aufgerufen. – RainierMallol

+0

Nun, in meinem Fall ist es. Sie sollten mehr Details zu den Daten in Ihrem Testfall angeben und feststellen, dass 'GetHashCode' nicht aufgerufen wird. –