Overriding == and != when overriding Equals()?

K

Kenneth Baltrinic

When one overrides the Equals() method of an object, one is supposed to
override GetHashCode() as well and this makes good sense. But I have seen
lots of people who do this and do not override the == and != opperators. Am
I missing something or when would one want to have different implementations
for Equals and ==?

--Ken
 
B

Bruce Wood

This depends upon whether your object is a reference type or a value
type.

The "unofficial" standard for reference types is that Equals compares
the _contents_ of the objects for equality (where you define what it
means for two objects to be "equal") whereas != and == tell you whether
two variables hold references to the _same object_.

In other words, the .NET standard is that Equals compares for
equivalence, whereas == and != compare for reference equality /
inequality.

For value types (structs), it's different: in that case you _should_
override == and !=, as there's no such thing as "reference equality"
for a value type.
 
B

Barry Kelly

Kenneth Baltrinic said:
When one overrides the Equals() method of an object, one is supposed to
override GetHashCode() as well and this makes good sense. But I have seen
lots of people who do this and do not override the == and != opperators. Am
I missing something or when would one want to have different implementations
for Equals and ==?

If you have a mutable reference type, it may be meaningful to compare it
with other types with (say) object.Equals(object,object), but because
the two references do not actually refer to the same object, you still
want reference-based comparison using the '==' and '!=' operators.

If you have an immutable reference type (such as System.String), it
makes much more sense to override '==' and '!='.

-- Barry
 
C

Chris Nahr

You already received two replies to your earlier identical question.
Did you not read them?
 
K

Kenneth Baltrinic

Interesting,

For some reason I can't see that previous message, nor its replies in my
news reader. I just figured the network hiccuped and my orriginal post
never made it onto the board so I reposted. I just looked again and I still
can't see the orriginal. The replies on the current thread message seem to
cover the bases. Do the replies to the previous one add anything?

--Ken
 
K

Kenneth Baltrinic

I agree and I think my code is a case of immutable objects. What I am doing
is using generics to produce strongly type Guid based object identifiers.
Basically if I declare a class A, rather than declaring an ID property as
type Guid I declare it as type Identifier<A> using the following code. This
gives me strong typing for situations where I have an overloaded method that
can act on various objects by ID but needs to know the object type as well.
Does this sound like a userful thing? I invite critisism. I like strong
typing but may be going a bit far here.

/// <summary>
/// This class encapsulates a Guid that is used as an identifier so that
strongly typed
/// Guid based identifer types can be derived from it. It is marked
abastract because
/// direct instatiation of this type would circumvent strong typing.
/// </summary>
[Serializable]
public abstract class GuidIdentifier
{
private Guid idValue;

/// <summary>
/// Creates a new GuidIdentifier object with a new Guid value.
/// </summary>
protected GuidIdentifier()
{
this.idValue = Guid.NewGuid();
}

/// <summary>
/// Creates a new GuidIdentifier object with the provided Guid as
its underlying value.
/// </summary>
/// <param name="value">The Guid value to which to intitialize the
identifer.</param>
protected GuidIdentifier( Guid value )
{
this.idValue = value;
}

/// <summary>
/// Returns the actual Guid value of the identifier.
/// </summary>
public Guid Value { get { return idValue; } }

public override bool Equals( object obj )
{
if ( obj.GetType() == this.GetType() )
return GuidIdentifier.Equals( this , (
GuidIdentifier )obj );
else
return false;
}

public override int GetHashCode()
{
return this.Value.GetHashCode();
}

public override string ToString()
{
return string.Format( "ID: {0:B}" , idValue );
}

public static bool operator ==( GuidIdentifier a , GuidIdentifier
b )
{
return GuidIdentifier.Equals( a , b );
}

public static bool operator !=( GuidIdentifier a , GuidIdentifier
b )
{
return !GuidIdentifier.Equals( a , b );
}

/// <summary>
/// Compares two GuidIdentifiers, returns true if their underlying
Guid values are the same.
/// </summary>
/// <param name="a"></param>
/// <param name="b"></param>
/// <returns>True if GuidIdentifier a.Value == GuidIdentifier
b.Value</returns>
public static bool Equals( GuidIdentifier a , GuidIdentifier b )
{
if ( object.Equals( a , null ) || object.Equals( b , null ) )
//will return true if both objects are null, false otherwise
return object.Equals( a , b );
else
return a.idValue == b.idValue;
}
}

/// <summary>
/// This class is a generic implementation of GuidIdentifier which
allows for
/// strongly typed Guid based identifiers that derive from a common base
class.
/// </summary>
/// <typeparam name="T">The type of the class of which
Identifier&lt;T&gt; identifies an instance.</typeparam>
public class Identifier<T> : GuidIdentifier where T : BusinessBase<T>
{
/// <summary>
/// Creates a new Identifier instance having a new Guid value;
/// </summary>
public Identifier() : base() { }

/// <summary>
/// Creates a new Identifier instance having the specified Guid
value;
/// </summary>
/// <param name="value">The Guid value of the identifier</param>
public Identifier( Guid value ) : base( value ) { }
}

Note I use the pattern where one defines a non-generic class that provides
for a common type for the generic sub-classes. (Is there a name for this
pattern? I see it used a lot but never see a name.)

Any comments or critisism would be appreciated.

--Ken
 
B

Barry Kelly

Kenneth Baltrinic said:
public override bool Equals( object obj )
{
if ( obj.GetType() == this.GetType() )
return GuidIdentifier.Equals( this , (
GuidIdentifier )obj );
else
return false;
}

Be aware that 'obj' may be null. This code will incorrectly throw a
NullReferenceException in that case.
public static bool Equals( GuidIdentifier a , GuidIdentifier b )
{
if ( object.Equals( a , null ) || object.Equals( b , null ) )
//will return true if both objects are null, false otherwise
return object.Equals( a , b );
else
return a.idValue == b.idValue;
}
}

That will work, but personally, I would write this method thusly:

---8<---
return object.ReferenceEquals(a, b)
|| !object.ReferenceEquals(a, null) && a.idValue == b.idValue;
--->8---

.... since && has higher precedence than ||.

Overriding Equals, '==', '!=' and providing a static Equals() all in a
consistent way is surprisingly tricky.

-- Barry
 
K

Kenneth Baltrinic

Barry,

Good catch on the potential null reference, Thanks. As for the other
method, yeah I should probably use ReferenceEquals() over equals, but I
think the structure of my code is more readable. All a matter of taste
though.
 
C

Chris Nahr

Sounds like your newsfeed was dropping a few messages. That can
happen in busy newsgroups like this one, unfortunately.

The previous two replies were more of a general nature. They're brief
enough to I'll just add the text below. Generally, you should be able
to get a complete newsfeed from http://groups.google.com , by the way.

Lee said:
I would overload the == and != operators where the underlying types are my
own value types to make the underlying code simpler to read since by default
there are no overloads for them. Also the default behavour for .Equals can
(depending on its members for value types) be to do a member wise compare
using reflection which is slower than if your roll with your own comparison
methods. Note also that you cannot "override" operators which implies
polymorphism rather you can overload them.
[Quote from your message] >Am
I missing something or when would one want to have different implementations
for Equals and ==?

Whenever one would expect to test for reference equality of reference
types, rather than value equality.

Equals has a sister method ReferenceEquals so the jobs are clearly
differentiated, but there's only one operator== which translates to
ReferenceEquals by default. You have to decide whether your users
would want/expect ReferenceEquals or Equals when they type ==. The
answer will be different for each type, depending on usage patterns.
 

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

Top