2010-10-12 4 views
1

Ci-dessous est un programme de test simple qui jette un StackOverflowException quand Equals est appelé. Je m'attendais au générique Equals que j'ai reçu de l'objet pour appeler mon IEquatable<MyClass>.Equals, mais ce n'est pas le cas, il s'appelle à la place. Pourquoi? Le type de paramètre semble correct. Pourquoi appelle-t-il la version générique en premier lieu? Je suis confus.Pourquoi une exception de dépassement de pile est-elle générée?

using System; 

namespace consapp 
{ 
    class Program 
    { 
     static void Main(string[] args) 
     { 
      MyClass x0 = new MyClass("x0"); 
      MyClass x1 = new MyClass("x"); 

      Console.WriteLine(x1.Equals(x0)); 
     } 

    } 

    internal class MyClass : IEquatable<MyClass> 
    { 
     public string Name { get; set; } 
     public MyClass(string s) { this.Name = s; } 
     public override bool Equals(object x) { return this.Equals(x as MyClass); } 
     public override int GetHashCode() { return this.Name.ToLowerInvariant().GetHashCode(); } 
     bool IEquatable<MyClass>.Equals(MyClass x) { return x != null && this.Name == x.Name; } 
    } 
} 
+0

Un problème que je vois est que vous n'avez pas défini la propriété Name dans la classe MyClass. Définissez une variable membre pour stocker une chaîne représentant un nom, puis obtenez/définissez-la à l'aide de la propriété Name. – Bernard

+0

D'un côté, vous n'avez probablement pas besoin de surcharger explicitement IEquatable; il surchargera juste bien avec la version d'Object et vous voudrez généralement exposer les Equals plus spécifiques pour des clients de votre classe. –

+0

@Dan: je ne suis pas sûr de ce que vous voulez dire. Je comprends la première partie où vous dites que je peux utiliser mon objet outrepassent l'implémentation comme implémentation IEquatable aussi, mais je ne comprends pas ce que vous voulez dire après cela. la deuxième partie semble contredire le début de la phrase :) – akonsu

Répondre

8

IEquatable.Equals est implémentée explicitement. Vous devez lancer la classe à l'interface première à utiliser une implémentation explicite:

public override bool Equals(object x) 
{ 
    return (this as IEquatable).Equals(x as MyClass); 
} 

Sinon, il va continuer à s'appeler dans une récursion infinie, ce qui donne dans un StackOverflowException finalement.

+0

merci. Je ne savais pas que les méthodes d'interface implémentées explicitement ne peuvent pas être appelées de la même manière que les méthodes non-interface. – akonsu

+0

C'est la raison pour laquelle vous utilisez des implémentations explicites - vous pouvez donc avoir différentes interfaces implémentant le même nom de méthode. – Femaref

+0

Dans ce cas cependant, il n'y a pas d'autre méthode avec la même signature, et il fera 'x.Equals (y)' 'où les deux x' et' 'y' sont MyClass' inutilement passer par la version moins spécifique. Je voudrais changer le 'Equals (MyClass)' pour être implicite et changer le 'Equals (object)' à la façon dont il était. –

0

Si vous voulez appeler les Equals de l'objet dans votre override égal, vous devez appeler base.Equals, pas this.Equals.

Et notez que ce equals compare simplement les références, pas le contenu.

+0

ce n'est pas la cause de l'erreur ici, il veut appeler l'implémentation d'interface explicite. – Femaref

0

Essayez

public override bool Equals(object x) { 
    Console.Write("equals! "); 
    return this.Equals(x as MyClass); 

} 
1

public override bool Equals(object x) { return this.Equals(x as MyClass); }
La ligne ci-dessus est à l'origine.

Vous devrez changer à

public override bool Equals(object x) 
{ 
    return ((IEquatable<MyClass>)this).Equals(x as MyClass); 
} 
Questions connexes