假设我们有这段代码:
Action<int> gf = k => { };
Action<int> gfa = k => { k++; };
我如何确定gf
没有正文或语句?
是否可以在 a 中获取语句数量Action
?
类似于GetNumberOfStatements(gf)
which should的东西return 0
。
或者也许 HasEmptyBody(gf) 应该return true
;
好吧,这有点不确定,但是您可以检查方法体的 IL 并检查它是否为空或完全由Nops组成(当然除了最后的 Ret )。
显然,如果编写该方法的编程语言的编译器已编译掉操作而没有任何影响,那么您将在这里得到误报。但我假设您主要对(arg1, arg2, ... ) => { }
C# 案例感兴趣,这应该可以正常工作。
public static bool IsEmpty(this Delegate del)
{
// Null arg-checking omitted.
short nop = System.Reflection.Emit.OpCodes.Nop.Value;
var ilArray = del.Method.GetMethodBody().GetILAsByteArray();
return ilArray.Take(ilArray.Length - 1).All(b => b == nop);
}
.Net 中的委托只不过是函数指针。就像您无法判断 .Net 方法中有多少 C# 语句一样,您也无法判断 .Net 委托中有多少条语句。部分原因是该方法不一定用 C# 或任何其他具有语句概念的语言编码。它可以直接用基于操作码的 IL 编写
编辑:决定在我等待构建服务器重新启动时稍微修改一下......
实际上,我的“实用程序库”周围有一些东西可能会对您有所帮助-自然,这里有很大的改进空间-这绝不是用于“生产用途”的:
public static void DumpMethod(Delegate method)
{
var mb = method.Method.GetMethodBody();
var il = mb.GetILAsByteArray();
var opCodes = typeof(System.Reflection.Emit.OpCodes)
.GetFields()
.Select(fi => (System.Reflection.Emit.OpCode)fi.GetValue(null));
var mappedIL = il.Select(op => opCodes.FirstOrDefault(opCode => opCode.Value == op));
var ilWalker = mappedIL.GetEnumerator();
while(ilWalker.MoveNext())
{
var mappedOp = ilWalker.Current;
if(mappedOp.OperandType != System.Reflection.Emit.OperandType.InlineNone)
{
var byteCount = 0;
long operand = 0;
switch(mappedOp.OperandType)
{
case System.Reflection.Emit.OperandType.InlineI:
case System.Reflection.Emit.OperandType.InlineBrTarget:
case System.Reflection.Emit.OperandType.InlineMethod:
case System.Reflection.Emit.OperandType.InlineField:
case System.Reflection.Emit.OperandType.InlineSig:
case System.Reflection.Emit.OperandType.InlineString:
case System.Reflection.Emit.OperandType.InlineType:
case System.Reflection.Emit.OperandType.InlineSwitch:
byteCount = 4;
break;
case System.Reflection.Emit.OperandType.InlineI8:
case System.Reflection.Emit.OperandType.InlineR:
byteCount = 8;
break;
}
for(int i=0; i < byteCount; i++)
{
ilWalker.MoveNext();
operand |= ((long)ilWalker.Current.Value) << (8 * i);
}
Console.WriteLine("{0} {1}", mappedOp.Name, operand);
}
else
{
Console.WriteLine("{0}", mappedOp.Name);
}
}
}
试验台:
Func<int,int> addOne = i => i + 1;
DumpMethod(addOne);
Console.WriteLine();
Func<int,string> stuff = i =>
{
var m = 10312;
var j = i + m;
var k = j * j + i;
var asStr = k.ToString();
return asStr;
};
DumpMethod(stuff);
输出:
ldarg.0
ldc.i4.1
add
ret
ldc.i4 10312
stloc.0
ldarg.0
ldloc.0
add
stloc.1
ldloc.1
ldloc.1
mul
ldarg.0
add
stloc.2
ldloca.s 0
ldarg.0
call 167772167
stloc.3
ldloc.3
ret