Stack Exchange
How to emit LDC_I8 for a ulong.Parse call?
I'm having an issue with emitting IL to set a uint64 property value.  Below is some minimal code to reproduce the issue.
using System;
using System.Reflection;
using System.Reflection.Emit;

namespace ConsoleApplication1
{
  class Program
  {
    static void Main(string[] args)
    {
      AssemblyBuilder assemblyBuilder = AppDomain.CurrentDomain.DefineDynamicAssembly(
        new AssemblyName("test"), AssemblyBuilderAccess.RunAndSave);
      ModuleBuilder m_moduleBuilder = assemblyBuilder.DefineDynamicModule("test.dll",
        "test.dll");
      TypeBuilder typeBuilder = m_moduleBuilder.DefineType("Class1",
        TypeAttributes.Public |
        TypeAttributes.Class |
        TypeAttributes.AutoClass |
        TypeAttributes.AnsiClass |
        TypeAttributes.BeforeFieldInit |
        TypeAttributes.AutoLayout, null);

      FieldBuilder fieldBuilder = typeBuilder.DefineField("m_prop1",
          typeof(ulong), FieldAttributes.Private);

      MethodBuilder getMethodBuilder = typeBuilder.DefineMethod(
        "get_prop1",
        MethodAttributes.Public | MethodAttributes.SpecialName |
        MethodAttributes.HideBySig,
        typeof(ulong), Type.EmptyTypes);
      ILGenerator getIlGen = getMethodBuilder.GetILGenerator();
      getIlGen.Emit(OpCodes.Ldarg_0);
      getIlGen.Emit(OpCodes.Ldfld, fieldBuilder);
      getIlGen.Emit(OpCodes.Ret);

      MethodBuilder setMethodBuilder = typeBuilder.DefineMethod(
        "set_prop1",
        MethodAttributes.Public | MethodAttributes.SpecialName |
        MethodAttributes.HideBySig,
        null, new[] { typeof(ulong) });
      ILGenerator setIlGen = setMethodBuilder.GetILGenerator();
      setIlGen.Emit(OpCodes.Ldarg_0);
      setIlGen.Emit(OpCodes.Ldarg_1);
      setIlGen.Emit(OpCodes.Stfld, fieldBuilder);
      setIlGen.Emit(OpCodes.Ret);

      PropertyBuilder propertyBuilder = typeBuilder.DefineProperty(
        "prop1", PropertyAttributes.HasDefault, typeof(ulong),
        null);
      propertyBuilder.SetGetMethod(getMethodBuilder);
      propertyBuilder.SetSetMethod(setMethodBuilder);

      ConstructorBuilder constructorBuilder =
        typeBuilder.DefineConstructor(MethodAttributes.Public,
        CallingConventions.Standard, Type.EmptyTypes);
      ILGenerator ilGenerator = constructorBuilder.GetILGenerator();
      ilGenerator.Emit(OpCodes.Ldarg_0);
      ilGenerator.Emit(OpCodes.Call,
        typeBuilder.BaseType.GetConstructor(Type.EmptyTypes));
      ilGenerator.Emit(OpCodes.Ldarg_0);
      ilGenerator.Emit(OpCodes.Ldc_I8, ulong.Parse("0"));
      ilGenerator.Emit(OpCodes.Call, propertyBuilder.GetSetMethod());
      ilGenerator.Emit(OpCodes.Ret);

      Type class1Type = typeBuilder.CreateType();

      assemblyBuilder.Save("test.dll");
    }
  }
}

If you run peverify on the created .dll you get the following:
[IL]: Error: [C:\code\ConsoleApplication1\ConsoleApplication1\bin\Debug\test.dl
 : Class1::.ctor][offset 0x00000010] Unrecognized local variable number.
1 Error(s) Verifying test.dll

If you dissassemble the constructor it looks like follows:
.method public specialname rtspecialname 
        instance void  .ctor() cil managed
{
  // Code size       18 (0x12)
  .maxstack  4
  IL_0000:  ldarg.0
  IL_0001:  call       instance void [mscorlib]System.Object::.ctor()
  IL_0006:  ldarg.0
  IL_0007:  ldc.i8     0x22800000000
  IL_0010:  ldloc.0
  IL_0011:  ret
} // end of method Class1::.ctor

So why is ilGenerator.Emit(OpCodes.Ldc_I8, ulong.Parse("0")); being turned into
IL_0007:  ldc.i8     0x22800000000 and what happened to the property set call?
Changing ulong.Parse to long.Parse gets it to create an assembly without these errors but then the long.Parse will crash if I feed it a value greater than long.MaxValue.

According to http://msdn.microsoft.com/en-us/library/x3aeheba.aspx Emit does not know anything about ulong as a second parameter (only Int64 which is signed)... see here too - MSDN says explicitely "signed long"...

Not an answer, but the usual way to denote a numeric literal of type ulong in C# is 0ul, so you could use ilGenerator.Emit(OpCodes.Ldc_I8, 0ul);. Edit: But see answer by Ian Griffith on what overload of Emit is actually called. An ulong converts to float implicitly.

That particular call to Emit ends up using the overload that accepts a float, due to the lack of a ulong-aware overload, as you've discovered since posting your original question. The funny-looking constant you see in ILDASM is mainly because that overload will only have emitted four bytes for the 0 value, but an 8 byte constant was expected, so it interpreted the following opcodes as the higher order bytes of the constant (which also explains why the property accessor call was apparently replaced with a completely different opcode).

The property accessor didn't vanish completely. It seems it was replaced by ldloc.0, precisely because of the byte number mismatch.

Solution could be to use overload that takes a signed long, so ilGenerator.Emit(OpCodes.Ldc_I8, 0L);. Edit:  An ulong converts to float implicitly.

@svick good point - I've edited my post to take this into account. Thanks.

The trick is to use the unchecked keyword to convert the ulong to a long to make the emit operation happy.
  ilGenerator.Emit(OpCodes.Ldc_I8, unchecked((long)ulong.Parse("0")));


You shouldn't need that unchecked there, unless you changed the default from unchecked to checked in project properties.

I agree. In this case, the type cast without the unchecked is enough.  I didn't try that because I saw that long val = (long)0xFFFFFFFFFFFFFFFF; will not compile. However, it will coerce a ulong to a long if instead of a literal value you are typecasting a ulong variable or method return value.  Anyone else find that inconsistency a bit confusing? I will accept Ian's answer for explaining why the IL looks the way it does. Thank you everyone for your responses!

Yeah, for casting of literals, the default is checked. I think that makes sense: if the compiler is sure overflow will happen, it's good that it tells you about it by reporting an error. But inconsistency certainly is confusing if you don't know about it.
