C#反射:如果......其他?

use*_*443 12 c# reflection reflection.emit system.reflection memory-address

我目前正面临运营商的新问题.使用以下代码,我想使输出与if ... else在C#中使用pair 时的输出相同.

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

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.Ldc_I4, 0);
g.Emit(OpCodes.Ceq);
g.Emit(OpCodes.Brtrue_S, );

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

Console.Read();
Run Code Online (Sandbox Code Playgroud)

我的问题是:

  1. 如何获取指令的地址以将其作为分支操作码的参数传递?
  2. 有什么区别BRBR_S,BrtrueBrtrue_S,BrfalseBrfalse_S和类似的说明?

谢谢.

gor*_*ric 9

  1. 您可以使用DefineLabelMarkLabel方法的组合来确定分支的目标位置.为此,请声明您需要的标签 - 类似于 equalnotequal.然后,您可以在IL中标记应该存在标签的斑点.完成此操作后,您可以将分支指令的目标设置为此标签.

    // Define labels
    Label equal = g.DefineLabel();
    Label notEqual = g.DefineLabel();
    Label endOfMethod = g.DefineLabel();
    // your logic here
    g.Emit(OpCodes.Brtrue_S, equal);
    g.MarkLabel(equal);
    // some code if they are equal
    g.MarkLabel(notEqual);
    // some code if they are not equal
    g.MarkLabel(endOfMethod); // this marks the return point
    g.Emit(OpCodes.Ret);
    
    Run Code Online (Sandbox Code Playgroud)
  2. 之间的区别Br,Brtrue以及Brfalse和他们_S 同行的是跳跃的长度.的_S表示短格式; 目标指令是来自下一条指令的1字节有符号偏移量.在标准(非短)形式中,目标由4字节偏移量表示.


Bot*_*000 8

ILGenerator.ILOffset如果你想要的话,它会给你IL流中的当前偏移量.你可以用DefineLabelMarkLabel,也因为goric建议.

之间唯一的区别brtrue.sbrtruebrtrue.s为短版brtrue.brtrue使用4字节偏移量并brtrue.s使用1字节偏移量.这同样适用于brfalsebrfalse.s(和br/ br.s).

这些不是IL指令的唯一短版本,还有其他简短指令,例如ldc.i4.0- ldc.i4.8用于加载整数.这些主要用于生成较小的二进制文件,但我认为不会有很大的区别.