Pergunta

I'm considering the instance method Object.Equals(Object). Using reflection, it is posible to get the IL for this method as a byte array, as follows:

var mi = typeof(object).GetMethod("Equals", BindingFlags.Instance | BindingFlags.Public);
var mb = mi.GetMethodBody();
var bytes = mb.GetILAsByteArray();

I have two PCs: one is a 32-bit machine running Windows XP, the other is 64-bit with Windows 7. Both machines have version 4.0.30319 SP1Rel of the .NET Framework installed.

On the x86 machine, the resulting array is:

[0]: 2
[1]: 3
[2]: 40
[3]: 122
[4]: 67
[5]: 0
[6]: 6
[7]: 42

On the x64 machine, though, I get this:

[0]: 2
[1]: 3
[2]: 40
[3]: 123
[4]: 67
[5]: 0
[6]: 6
[7]: 42

The fourth byte is different.

Now I know that mscorlib comes in two flavours on 64-bit platforms. However, ILDASM reveals that the IL for this method is identical between flavours and between machines. On the x64 machine I have targeted the above code at both "Any CPU" and "x86" but the result is the same.

So my question is, can anyone account for the noted discrepancy between the two machines?

UPDATE

Here's the C# and IL for Object.Equals(Object):

public virtual bool Equals(object obj)
{
    return RuntimeHelpers.Equals(this, obj);
}

.maxstack  8
IL_0000:  ldarg.0
IL_0001:  ldarg.1
IL_0002:  call bool System.Runtime.CompilerServices.RuntimeHelpers::Equals(object, object)
IL_0007:  ret
Foi útil?

Solução

Get better insight in the IL content by just writing the method your self and looking at it with ildasm.exe. Use View + Show bytes in ildasm to see the byte values, note that they are in hex:

.method public hidebysig newslot virtual 
        instance bool  Equals(object obj) cil managed
// SIG: 20 01 02 1C
{
  // Method begins at RVA 0x2052
  // Code size       8 (0x8)
  .maxstack  8
  IL_0000:  /* 02   |                  */ ldarg.0
  IL_0001:  /* 03   |                  */ ldarg.1
  IL_0002:  /* 28   | (0A)000010       */ call       bool [mscorlib]System.Runtime.CompilerServices.RuntimeHelpers::Equals(object,
                                                                                                                           object)
  IL_0007:  /* 2A   |                  */ ret
} // end of method Program::Equals

You'll now see that the byte at IL_0003 is part of a method token, the least significant byte of it. And note how the value I got is drastically different from the one you got. Which is because I just wrote a very small program with very little code to test it, it has a very small manifest. The disassembler is being helpful, instead of only displaying the token value it actually did the lookup in the metadata table and replaced the token with the method name.

A token is an index in the assembly manifest's metadata tables. Such an index will change when the code in the assembly changes and requires an addition to the tables. You can read more about it in the CLI spec, ECMA 335.

Outras dicas

The differing byte is a part of the metadata token referring to RuntimeHelpers.Equals(). Metadata tokens are not guaranteed to be stable when a module is recompiled. That's why binding to symbols in other assemblies happens by name and not by metadata token.

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top