Overriding operators

  • Thread starter Thread starter Microsoft Newsserver
  • Start date Start date
M

Microsoft Newsserver

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


}
 
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
 
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;

}
 
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);
}
}
 
Microsoft Newsserver said:
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.

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.)
 
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
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
}

//Operator Overrides - ( Duration Comparison )

public static bool operator ==(Slot s1, Slot s2)

{

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)

return true;

else return false;

}

Hans Kesting
 
Hans Kesting said:
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.
 
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;

}
 
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
 
Hans said:
see inline

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.
 
Microsoft said:
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;

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)

return true;

else return false;

}

public static bool operator !=(Slot s1, Slot s2)

{

instead:

return !(s1 == s2);
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Back
Top