.NET Forum / Languages / C# / February 2008
Overriding operators
|
|
Thread rating:  |
Microsoft Newsserver - 19 Feb 2008 11:23 GMT Hi
I have a class which I have overridden the operators and it woks fine. But when I try and test for the following. It fails. I need to know how to test equality for Nulls, before I test for the euqlity of the object, how can I do this ?
MyClassInstance=null;
if( MyClassInstance!=null ) {
still gets
}
Marc Gravell - 19 Feb 2008 11:38 GMT Are you looking for ReferenceEquals(MyClassInstance, null) ?
However, your example is confusing - looks to me like a very confusing operator implementation if a null instance reports itself as not equal to null... can't say more without looking at the operator code.
Marc
Microsoft Newsserver - 19 Feb 2008 11:43 GMT Hi Marc
Thanks for your reply. This is some of the implementation. Basically the equality test is working ok when the class has been instantiated. Unfortuneatly, when I have set the class to = null; and I want to test that, it fails of course, and I need to know how to properly code it so I can test for a null value as the overloads are static. I have tried to test s1,s2 for nulls, but of course I get a stack overflow exception. Operator overloading isnt something ive dont much of before so yoru advice is helpful. I tried the referenceequals function but that fails in my scanario.
Many thanks.
public override int GetHashCode()
{
return base.GetHashCode();
}
public override bool Equals(object obj)
{
return base.Equals(obj);
}
//Operator Overrides - ( Duration Comparison )
public static bool operator ==(Slot s1, Slot s2)
{
if (s1.startTimeID == s2.startTimeID && s1.endTimeID == s2.endTimeID)
return true;
else return false;
}
> Are you looking for ReferenceEquals(MyClassInstance, null) ? > [quoted text clipped - 3 lines] > > Marc Marc Gravell - 19 Feb 2008 12:03 GMT OK; that is going to break when nulls are involved, so simply deal with those separately (see below); most of the code is AreEqual - first we handle "are they the same instance" (which also handles "are they both null") - if so, must be the same. Then if *either* is null (by itself) then they can't be equal. So now we've excluded every case involving null; *now* we can worry about the field equality.
Note also that I've made Equals() consistent with these rules (reports false if it is compared to something that isn't a Slot), and I've provided a meaningful hash implementation (so you can use the object in a dictionary/hashtable).
Does that work any better? To be honest, I'm not 100% sure how far you got, so rather than me prattle on, if you have any specific questions, please ask?
Marc
using System; class Slot : IEquatable<Slot> { private int startTimeId, endTimeId; public override int GetHashCode() { return (17 * startTimeId.GetHashCode()) + endTimeId.GetHashCode(); }
public override bool Equals(object obj) { Slot slot = obj as Slot; return slot == null ? false : AreEqual(this, slot); } public bool Equals(Slot slot) { return AreEqual(this, slot); }
private static bool AreEqual(Slot s1, Slot s2) { if (ReferenceEquals(s1, s2)) return true; if (ReferenceEquals(s1, null) || ReferenceEquals(s2, null)) return false;
return s1.startTimeId == s2.startTimeId && s1.endTimeId == s2.endTimeId; } public static bool operator ==(Slot s1, Slot s2) { return AreEqual(s1, s2); } public static bool operator !=(Slot s1, Slot s2) { return !AreEqual(s1, s2); } }
Jon Skeet [C# MVP] - 19 Feb 2008 12:06 GMT > Thanks for your reply. This is some of the implementation. Basically the > equality test is working ok when the class has been instantiated. [quoted text clipped - 5 lines] > helpful. I tried the referenceequals function but that fails in my > scanario. ReferenceEquals *is* what you're after, so could you post a short but complete program which demonstrates the problem, attempting to use ReferenceEquals?
See http://www.pobox.com/~skeet/csharp/complete.html for details of what I mean by "short but complete program".
(I have to say that overloading == but leaving Equals and GetHashCode doing their original comparisons is somewhat confusing behaviour.)
 Signature Jon Skeet - <skeet@pobox.com> http://www.pobox.com/~skeet Blog: http://www.msmvps.com/jon.skeet World class .NET training in the UK: http://iterativetraining.co.uk
Hans Kesting - 19 Feb 2008 12:10 GMT see inline
> public override bool Equals(object obj) > > { if ( obj == null || ! (obj is Slot)) return false; // "Slot" (this) against non-Slot: fail
Slot other = (Slot)obj; // and now compare similar to the == operator
> } > [quoted text clipped - 3 lines] > > { if (s1 == null && s2 == null) return true; // both null: so equal if (s1 == null || s2 == null) return false; // one is null, the other not: not equal
> if (s1.startTimeID == s2.startTimeID && s1.endTimeID == s2.endTimeID) > [quoted text clipped - 3 lines] > > } Hans Kesting
Microsoft Newsserver - 19 Feb 2008 12:07 GMT Thanks guys.
I will look into this further having read your replies and get back to you, thank you very much for your assistance.
> see inline > [quoted text clipped - 30 lines] > > Hans Kesting Jon Skeet [C# MVP] - 19 Feb 2008 12:18 GMT > > //Operator Overrides - ( Duration Comparison ) > > [quoted text clipped - 4 lines] > if (s1 == null && s2 == null) > return true; // both null: so equal Bang! Stack overflow. The above will call operator == again, recursing. You need to either cast to object, or use object.ReferenceEquals. I personally find the latter more explicit.
 Signature Jon Skeet - <skeet@pobox.com> http://www.pobox.com/~skeet Blog: http://www.msmvps.com/jon.skeet World class .NET training in the UK: http://iterativetraining.co.uk
Microsoft Newsserver - 19 Feb 2008 12:32 GMT This seems to work ok, thank you all for your help.
//Operator Overrides - ( Duration Comparison )
public static bool operator ==(Slot s1, Slot s2)
{
if (ReferenceEquals(s1, null) && ReferenceEquals(s2, null)) return true;
if (!ReferenceEquals(s1, null) && ReferenceEquals(s2, null)) return false;
if (s1.startTimeID == s2.startTimeID && s1.endTimeID == s2.endTimeID)
return true;
else return false;
}
public static bool operator !=(Slot s1, Slot s2)
{
if( ReferenceEquals(s1, null) && ReferenceEquals(s2,null)) return false;
if( !ReferenceEquals(s1, null) && ReferenceEquals(s2,null)) return true;
if (s1.startTimeID != s2.startTimeID || s1.endTimeID != s2.endTimeID)
return true;
else return false;
}
>> > //Operator Overrides - ( Duration Comparison ) >> > [quoted text clipped - 8 lines] > You need to either cast to object, or use object.ReferenceEquals. I > personally find the latter more explicit. Marc Gravell - 19 Feb 2008 12:42 GMT For the record - there is a reason that the compiler warning prompts you to override Equals() and GetHashCode() - so you really should provide something sensible here. Also, to reduce maintenance overhead, I do recommend only having the "real" code once (rather than separately in == and !=) - you could call one from the other, for example (and simply negate the result).
Marc
Microsoft Newsserver - 19 Feb 2008 12:44 GMT noted.
Thank you.
> For the record - there is a reason that the compiler warning prompts you > to override Equals() and GetHashCode() - so you really should provide [quoted text clipped - 4 lines] > > Marc Ben Voigt [C++ MVP] - 19 Feb 2008 19:29 GMT > This seems to work ok, thank you all for your help. > [quoted text clipped - 6 lines] > if (ReferenceEquals(s1, null) && ReferenceEquals(s2, null)) return > true; instead:
if (ReferenceEquals(s1, s2)) return true;
> if (!ReferenceEquals(s1, null) && ReferenceEquals(s2, null)) return > false; That needs to be ||, not &&
> if (s1.startTimeID == s2.startTimeID && s1.endTimeID == s2.endTimeID) > [quoted text clipped - 7 lines] > > { instead:
return !(s1 == s2);
> if( ReferenceEquals(s1, null) && ReferenceEquals(s2,null)) return > false; [quoted text clipped - 26 lines] >> http://www.pobox.com/~skeet Blog: http://www.msmvps.com/jon.skeet >> World class .NET training in the UK: http://iterativetraining.co.uk Jeroen Mostert - 19 Feb 2008 18:19 GMT > see inline > [quoted text clipped - 3 lines] >> > if ( obj == null || ! (obj is Slot)) No. This should be
if (obj == null || obj.GetType() != this.GetType())
because Slot is a class, and "is" returns true for any class derived from Slot too. It is possible the comparison defined in Slot is still correct for derived classes, but there's no reason to force it to be.
If the derived class adds fields and overrides .Equals to compare for these, using "is" becomes flat-out wrong, because it could mean that aSlot.Equals(aDerivedSlot) is true but aDerivedSlot.Equals(aSlot) is false, which breaks the contract for .Equals().
Using "is" does work for structs and sealed classes, but even there .GetType() isn't wrong.
 Signature J.
Free MagazinesGet these publications absolutely FREE for up to 12 months. There are no hidden fees and no obligation. Simply choose a title, complete the application form and submit it. Read more ...
|
|
|