.NET: Where is the default implementation for "==" op_Equality () for value types?

I went to .NET Reflector and noticed that there is an explicit overload of the "==" operator for reference types like "String" for example:

typeof(string).GetMethod("op_Equality", BindingFlags.Static | BindingFlags.Public)

      

returns: System.Reflection.MethodInfo for the "==" operator.

Due to its implementation, you cannot do things like:

if("hi" == 3)  // compiler error, plus code would throw an exception even if it ran)

      

However, the same works for value types:

if((int)1 == (float)1.0)  // correctly returns true
if((int)1 == (float)1.2)  // correctly returns false

      

I'm trying to figure out how .NET handles the type conversion process, so I looked for an op_Equality () implementation in .NET Reflector, but "int" doesn't have that.

typeof(int).GetMethod("op_Equality", BindingFlags.Static | BindingFlags.Public)

      

returns null.

So where is the default implementation for the "==" operator for value types? I would like it to be called reflection:

public bool AreEqual(object x, object y)
{
    if(x.GetType().IsValueType && y.GetType().IsValueType)
        return x == y; // Incorrect, this calls the "object" equality override
    else
        ...
}

      


Edit # 1:

I tried this but it didn't work:

(int)1 == (float)1;                          // returns true
System.ValueType.Equals( (int)1, (float)1 ); // returns false

      


Edit # 2:

And tried this but didn't like:

object x = (int)1;
object y = (float)1.0;

bool b1 = (x == y);                 // b1 = false
bool b2 = ((ValueType)x).Equals(y); // b2 = false

      

I believe this .Equals operator in ValueType is not working due to checking this type (broke from .NET Reflector):

ValueType.Equals(object obj)
{
    ...

    RuntimeType type = (RuntimeType) base.GetType();
    RuntimeType type2 = (RuntimeType) obj.GetType();
    if (type2 != type)
    {
        return false;
    }

    ...

      

0


a source to share


5 answers


the score (int) 1 == (float) 1.0 does not depend on any special operator ==, but only on the conversion rules.

The compiler will turn this into (float) ((int) 1) == (float) 1.0



Edit: The rules are listed on MSDN .

+2


a source


What you are looking for is ValueType.Equals

In many cases, this is simply a bit-by-bit comparison. In some cases though, it will use reflection to validate fields.



EDIT

You are confusing how C # compares value types and how .Net compares value types. ValueType.Equals is a function in .Net used to compare value type objects that have the same type. C # will emit code that ultimately calls this function. But this is not called "int" and "float". Instead, it first converts both of them to a type that does not lose precision for the (double) value, and then compares the resulting double values. This is why you see the difference in behavior.

+2


a source


Where is the default implementation for ==

op_Equality

for value types used?

There is no default for value types ==

. Try to write your own value type

struct JustAnotherValueType
{
  public readonly int Field;
  public JustAnotherValueType(int f) { Field = f; }
}

      

Make two values x

and y

your type. Try to talk x == y

to them. It won't compile. You can tell

(object)x == (object)y

      

but it will do boxing on x

(let it come out in box 1) and boxing on y

(box 2), and then do the comparison in two blocks. Hence, it will always return false. And so it's useless, and the reason why the overload is ==(object x, object y)

not automatically chosen when used ==

between the two JustAnotherValueType

.

So what happens to int

and float

? You can compare them to ==

in C # and they don't have a method op_Equality

?! The explanation is that these overloads are defined by the C # language specification . See Sections Integer Comparison Operators and Floating Point Comparison Operators.

Thus, the fact is that while these operators do not exist as members of .NET structures, the C # language specification defines them, and the C # compiler must emit some valid IL to mimic their behavior.

By the way, it System.Object

also does not op_Equality

. It is also only defined by C #. See Section Equality Operators of Reference Type. Note that there System.Object

is a method ReferenceEquals

that the compiler can choose to translate this overload ==

to. Also note that this section of the spec is limiting so it x == y

will never box on x

or y

.

What about value types such as DateTime

, TimeSpan

and Guid

, which are not mentioned in the C # spec, but for which it is legal to use ==

? Answer: These do have a member op_Equality

.

Conclusion. The C # Language Specification defines many overloads ==

that a C # implementation must have, and some of these overloads include int

and float

and object

.

Note. A virtual instance method is Equals(object)

defined in object

and inherited by all value types. For structures that do not override this method, use override

in System.ValueType

. It is compared by value. So, x

and y

as above x.Equals(y)

will work fine. Equals

- virtual instance method. On the other hand, it ==

is a method static

"that performs overload resolution based on the compile-time types of the two operands (no" virtual dispatch ").

+2


a source


I am assuming you are looking for ValueType.Equals (an obj object) that inherits to your structs. It uses reflection to compare all fields.

+1


a source


My answer to another question provides a rotor implementation. The actual code is implemented in the CLR as native code.

In particular:

// Compare the contents (size - vtable - sink block index).
BOOL ret = memcmp(
    (void *) (pThisRef+1), 
    (void *) (pCompareRef+1), 
    pThisRef->GetMethodTable()->GetBaseSize() - sizeof(Object) - sizeof(int)) == 0;

      

+1


a source







All Articles