OK, I don't see a comprehensive Answer right now, so I need to explain everything.
Basically, when you use "==" you don't compare object by referential identity. The result depends on comparison operator defined in class.
I don't know how you get your result, but let's test is correctly:
System.Guid g1 = System.Guid.Empty;
System.Guid g2 = System.Guid.Empty;
bool semanticallyEqual = g1 == g2;
bool referentiallyEqual = object.ReferenceEquals(g1, g2);
bool isTheSame = g1.Equals(g2);
Just to finally amaze you:
string s1 = "a";
string s2 = "a";
bool equalStrRef = object.ReferenceEquals(s1, s2);
The class
System.String
is very special, quite different from all other classes! The idea is extreme reuse of memory but exact simulation of
value semantic.
Let's illustrate modification of equality rules:
public class IdentitySample {
public IdentitySample(int intValue, string stringValue) {
this.FIntValue = intValue;
this.FStringValue = stringValue;
}
public int IntValue { get { return FIntValue; } }
public string StringValue { get { return FStringValue; } }
public override int GetHashCode() {
return FIntValue.GetHashCode() ^ FStringValue.GetHashCode();
}
public override bool Equals(object obj) {
if (object.ReferenceEquals(obj, null)) return false;
IdentitySample sameTypeObject = obj as IdentitySample;
if (object.ReferenceEquals(sameTypeObject, null)) return false;
return
sameTypeObject.FIntValue == this.FIntValue &&
sameTypeObject.FStringValue == this.FStringValue;
}
public static bool operator ==(IdentitySample left, IdentitySample right) {
if (object.ReferenceEquals(left, null) && (object.ReferenceEquals(right, null)))
return true;
else if (object.ReferenceEquals(left, null) && (!object.ReferenceEquals(right, null)))
return false;
else if (!object.ReferenceEquals(left, null) && (object.ReferenceEquals(right, null)))
return false;
else
return left.Equals(right);
}
public static bool operator !=(IdentitySample left, IdentitySample right) {
return !(left == right);
}
int FIntValue;
string FStringValue;
}
Consider the following important items here:
In the implementation, you cannot any longer use "
==
" for comparison, must use
object.ReferenceEquals
, otherwise you can run into infinite recursion.
The syntax will not allow your to define
==
or
!=
, along, it will require that both are defined.
A very important override is
object.GetHashCode
. If it is not overridden, compilation would fail. Here is why: you can store the instances of your class in a container like
Dictionary which uses
buckets technique for structuring item data and fast search (the complexity is estimated as
O(1)
!). The technique is based on the hash codes. The semantically different instances should have higher probability of having different hash code. So, in your implementation of this method you should take into account semantically significant members (only). Also, using XOR operator if a very reasonable choice; it eliminated wrapping over of integers (which would take place if you would add integers) but not ignore information on differences between different values. (To understand what I mean, take two bitmaps and XOR them, then XOR two more times…)
—SA