Search code examples
c#reflectionif-statementreflection.emitsystem.reflection

C# reflection if: 0 equals 1?


I have problem. This is my code:

var method = new DynamicMethod("dummy", null, Type.EmptyTypes);
var g = method.GetILGenerator();
g.DeclareLocal(typeof(int));

Label inequality = g.DefineLabel();
Label equality = g.DefineLabel();
Label end = g.DefineLabel();

g.Emit(OpCodes.Ldstr, "string");
g.Emit(OpCodes.Ldstr, "string");
g.Emit(OpCodes.Call, typeof(String).GetMethod("op_Equality", new Type[]{typeof(string), typeof(string)}));
g.Emit(OpCodes.Stloc_0);
g.Emit(OpCodes.Ldloc_0);
g.Emit(OpCodes.Call, typeof(Console).GetMethod("WriteLine", new Type[]{typeof(int)}));
g.Emit(OpCodes.Ldloc_0);
g.Emit(OpCodes.Ldc_I4_1);
g.Emit(OpCodes.Ceq);
g.Emit(OpCodes.Brtrue_S, equality);
g.Emit(OpCodes.Brfalse_S, inequality);
g.MarkLabel(inequality);
g.Emit(OpCodes.Ldstr, "Specified strings are different.");
g.Emit(OpCodes.Call, typeof(Console).GetMethod("WriteLine", new Type[]{typeof(string)}));
g.Emit(OpCodes.Br_S, end);
g.MarkLabel(equality);
g.Emit(OpCodes.Ldstr, "Specified strings are same.");
g.Emit(OpCodes.Call, typeof(Console).GetMethod("WriteLine", new Type[] { typeof(string) }));
g.Emit(OpCodes.Br_S, end);
g.MarkLabel(end);
g.Emit(OpCodes.Ret);

var action = (Action)method.CreateDelegate(typeof(Action));
action();

This is my result:

1
Specified strings are different.

But why is output wrong? Ceq instruction is comparing 1 as result from op_Equation and 0 which is on the top of stack. And 1 not equals 0. So why it is? Where is error? Please help me.


Solution

  • After g.Emit(OpCodes.Brtrue_S, inequality);, you need to jump to the "equality" statement manually. Else it will execute the next instruction anyway. So you'll need to insert the following line after it:

    g.Emit(OpCodes.Br_S, equality);
    

    Also, it doesn't make sense to jump to the label equality when it is declared as the next instruction anyway. So remove that.

    so the section will look like this:

    g.Emit(OpCodes.Ceq);
    
    g.Emit(OpCodes.Brtrue_S, inequality); // if true goto inequality
    g.Emit(OpCodes.Br_S, equality); // else goto equality
    
    g.MarkLabel(inequality);            
    g.Emit(OpCodes.Ldstr, "Specified strings are different.");
    g.Emit(OpCodes.Call, typeof(Console).GetMethod("WriteLine", new Type[]{typeof(string)}));
    g.Emit(OpCodes.Br_S, end); // goto end
    
    g.MarkLabel(equality);
    g.Emit(OpCodes.Ldstr, "Specified strings are same.");
    g.Emit(OpCodes.Call, typeof(Console).GetMethod("WriteLine", new Type[] { typeof(string) }));
    
    g.MarkLabel(end);
    g.Emit(OpCodes.Ret);