473,287 Members | 1,629 Online
Bytes | Software Development & Data Engineering Community
Post Job

Home Posts Topics Members FAQ

Join Bytes to post your question to a community of 473,287 software developers and data experts.

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

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
May 15 '06 #1
8 3685
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.

May 15 '06 #2
"Kenneth Baltrinic" <no***************@nowhere.xyz> wrote:
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
May 15 '06 #3
You already received two replies to your earlier identical question.
Did you not read them?
--
http://www.kynosarges.de
May 16 '06 #4
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

"Chris Nahr" <ch************@kynosarges.de> wrote in message
news:2k********************************@4ax.com...
You already received two replies to your earlier identical question.
Did you not read them?
--
http://www.kynosarges.de

May 16 '06 #5
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

"Barry Kelly" <ba***********@gmail.com> wrote in message
news:g8********************************@4ax.com...
"Kenneth Baltrinic" <no***************@nowhere.xyz> wrote:
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

May 16 '06 #6
"Kenneth Baltrinic" <no***************@nowhere.xyz> wrote:
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
May 16 '06 #7
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.

"Barry Kelly" <ba***********@gmail.com> wrote in message
news:37********************************@4ax.com...
"Kenneth Baltrinic" <no***************@nowhere.xyz> wrote:
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

May 16 '06 #8
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 Alexander wrote:
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.
Chris Nahr (me) wrote:[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.

--
http://www.kynosarges.de
May 17 '06 #9

This thread has been closed and replies have been disabled. Please start a new discussion.

Similar topics

4
by: Rafael Veronezi | last post by:
I have some questions about override in inheritance, and virtual members. I know that you can you override a method by two ways in C#, one, is overriding with the new keyword, like: public new...
12
by: Rubbrecht Philippe | last post by:
Hi there, According to documentation I read the ArrayList.IndexOf method uses the Object.Equals method to loop through the items in its list and locate the first index of an item that returns...
18
by: JohnR | last post by:
From reading the documentation, this should be a relatively easy thing. I have an arraylist of custom class instances which I want to search with an"indexof" where I'm passing an instance if the...
3
by: Kenneth Baltrinic | last post by:
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...
10
by: r035198x | last post by:
The Object class has five non final methods namely equals, hashCode, toString, clone, and finalize. These were designed to be overridden according to specific general contracts. Other classes that...
2
isladogs
by: isladogs | last post by:
The next Access Europe meeting will be on Wednesday 7 Feb 2024 starting at 18:00 UK time (6PM UTC) and finishing at about 19:30 (7.30PM). In this month's session, the creator of the excellent VBE...
0
by: MeoLessi9 | last post by:
I have VirtualBox installed on Windows 11 and now I would like to install Kali on a virtual machine. However, on the official website, I see two options: "Installer images" and "Virtual machines"....
0
by: DolphinDB | last post by:
The formulas of 101 quantitative trading alphas used by WorldQuant were presented in the paper 101 Formulaic Alphas. However, some formulas are complex, leading to challenges in calculation. Take...
0
by: DolphinDB | last post by:
Tired of spending countless mintues downsampling your data? Look no further! In this article, you’ll learn how to efficiently downsample 6.48 billion high-frequency records to 61 million...
0
by: Aftab Ahmad | last post by:
Hello Experts! I have written a code in MS Access for a cmd called "WhatsApp Message" to open WhatsApp using that very code but the problem is that it gives a popup message everytime I clicked on...
0
by: marcoviolo | last post by:
Dear all, I would like to implement on my worksheet an vlookup dynamic , that consider a change of pivot excel via win32com, from an external excel (without open it) and save the new file into a...
1
isladogs
by: isladogs | last post by:
The next Access Europe meeting will be on Wednesday 6 Mar 2024 starting at 18:00 UK time (6PM UTC) and finishing at about 19:15 (7.15PM). In this month's session, we are pleased to welcome back...
0
by: Vimpel783 | last post by:
Hello! Guys, I found this code on the Internet, but I need to modify it a little. It works well, the problem is this: Data is sent from only one cell, in this case B5, but it is necessary that data...
0
by: ArrayDB | last post by:
The error message I've encountered is; ERROR:root:Error generating model response: exception: access violation writing 0x0000000000005140, which seems to be indicative of an access violation...

By using Bytes.com and it's services, you agree to our Privacy Policy and Terms of Use.

To disable or enable advertisements and analytics tracking please visit the manage ads & tracking page.