The C# Reference states that for value types:
The ValueType.Equals(Object) method overrides Object.Equals(Object) and provides the default implementation of value equality for all value types in the .NET Framework.
If none of the fields of the current instance and obj are reference types, the Equals method performs a byte-by-byte comparison of the two objects in memory. Otherwise, it uses reflection to compare the corresponding fields of obj and this instance.
https://msdn.microsoft.com/en-us/library/2dts52z7(v=vs.110).aspx
As such since int is a value type I would expect that a simple wrapper for an int, would be equal to the int it wrapped, since it is the same on a byte by byte comparison - they both only contain a single int:
public struct Id
{
public Id(int id)
{
Id = id;
}
public int Id { get; }
}
Console.WriteLine(new Id(17).Equals(17);
But it actually prints false. Why is this?
These aren't the same type. Though the text doesn't explicitly say that, the Equals
method checks that they are the same type.
So this would work:
new Id(17).Equals(new Id(17));
If you want to handle comparison of two different types on your struct, you need to override Equals
and handle that yourself.
The relevant source is:
public abstract class ValueType {
[System.Security.SecuritySafeCritical]
public override bool Equals (Object obj) {
BCLDebug.Perf(false, "ValueType::Equals is not fast. "+this.GetType().FullName+" should override Equals(Object)");
if (null==obj) {
return false;
}
RuntimeType thisType = (RuntimeType)this.GetType();
RuntimeType thatType = (RuntimeType)obj.GetType();
if (thatType!=thisType) {
return false;
}
Object thisObj = (Object)this;
Object thisResult, thatResult;
// if there are no GC references in this object we can avoid reflection
// and do a fast memcmp
if (CanCompareBits(this))
return FastEqualsCheck(thisObj, obj);
FieldInfo[] thisFields = thisType.GetFields(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
for (int i=0; i<thisFields.Length; i++) {
thisResult = ((RtFieldInfo)thisFields[i]).UnsafeGetValue(thisObj);
thatResult = ((RtFieldInfo)thisFields[i]).UnsafeGetValue(obj);
if (thisResult == null) {
if (thatResult != null)
return false;
}
else
if (!thisResult.Equals(thatResult)) {
return false;
}
}
return true;
}
As you can see, it validates that the type of the arguments match before it checks the bytes. Since your type is not an int
, it'll always return false.
In general, the Equals
method of an object will not consider it equal to any object of any other type, even if both objects would encapsulate the same value.
Because of overloading, the act of passing values of certain types to the Equals methods of other types may cause them to get converted to the same type as the original. For example, (16777216.0f).Equals(16777217)
will select the overload Equals(float)
, convert the int
value 16777217
into the nearest float
value (ie 16777216.0f
) which will in turn compare equal to 16777216.0f
. This behavior could be prevented by converting either operand to object
, as in ((object)16777.216.0f).Equals(16777216)
or (16777.216.0f).Equals((object)16777216)
, either of which would report a float
object as unequal to an int
object (even though they hold the same numerical value).
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.