Search code examples
c#reflection.emitintermediate-language

How to use conditional in Reflection.Emit


Hello i am generating a class using Reflection.Emit and i want to know how do you use brfalse command for conditionals.

Specifically i do not know how do i translate the IL to OPCODES for the brfalse.s command.

My method has the following form:

object MyMethod() { if(isTransaction) //isTransaction is a bool property return Method1(); else return Method2(); }

Conditional

        IL_0000: ldarg.0      // this
        IL_0001: call         instance bool RediusTests.DaemonBase::get_IsTransaction()
        IL_0006: brfalse.s    IL_0020    //how is this translated within opcodes?

First branch:

        IL_0008:ldarg_0
        IL_.......          ///INSTRUCTIONS
        IL_......
        IL_001f:ret

Second branch:

        IL_0020:ldarg_0     //How do i specify with OPCODES to jump here?????
        IL_.......          
        IL_......
        IL_001f:ret

For the first snippet what would be the argument of brfalse.s?

        ilgen.Emit(OpCodes.Ldarg_0);
        ilgen.Emit(OpCodes.Call, getIsTransaction);
        ilgen.Emit(OpCodes.Brfalse,);  //what do i put here in the overload?

As you can see in the last snippet ,last line ,what should i put in the overload of ilgen.Emit? Nothing , 20 or is there some other code for translating to IL_0020?

Also isn't the address of the instruction stored at different address of memory on every run of program?Couldn't it change from IL0020 to IL00xx at future executions?

P.S After receiveing some comprehensive answers this is my version so far:

        ILGenerator ilgen = newMethod.GetILGenerator();
        Label falseLabel = ilgen.DefineLabel();
        Label continueLabel = ilgen.DefineLabel();

        ilgen.Emit(OpCodes.Ldarg_0);       
        ilgen.Emit(OpCodes.Call, getIsTransaction);
        ilgen.Emit(OpCodes.Brtrue,continueLabel);   //branching

        ilgen.MarkLabel(continueLabel);    //true branch
        ----instructions------
        ilgen.Emit(OpCodes.Ret);
        ilgen.Emit(OpCodes.Br,continueLabel);

        ilgen.MarkLabel(falseLabel);     //false branch
        --instructions----
        ilgen.Emit(OpCodes.Ret);

Solution

  • You never have to deal with code addresses explicitly. In order to jump, you need to define labels:

    Label falseLabel = ilgen.DefineLabel();
    Label continueLabel = ilgen.DefineLabel();
    
    ilgen.Emit(OpCodes.Call, getIsTransaction);
    ilgen.Emit(OpCodes.Brfalse, continueLabel);
    
    // getIsTransaction returned true
    ...
    
    ilgen.Emit(OpCodes.Br, continueLabel);
    
    ilgen.MarkLabel(falseLabel);
    // getIsTransaction returned false
    ...
    
    ilgen.MarkLabel(continueLabel);