题
我有几个特殊的方法,我想分析它们在编译的程序集中的调用。
例子:
public static class SrcHelper {
[MySpecialMethod]
[Conditional( "DEBUG" )]
public static void ToDo( params object[] info ) {
/* do nothing */
/* this method is not called when code is compiled in RELEASE mode */
}
}
// ... somewhere else in another assembly ...
Array CreateArraySampleMethod( int size ) {
// This call has only informative character. No functionality is required.
SrcHelper.ToDo( "Should create array of ", typeof( MyClass ), " with specified size." );
throw new NotImplementedException();
}
在此编译的代码中,我希望获得参数值{“应该创建“ MyClass”的数组,“指定大小”。 }。我尝试使用 Mono 中的 Cecil,并找到了调用“ToDo”方法的说明。但现在我很困惑如何识别带有参数值的指令。
我知道,情况可能很复杂,有些争论的价值无法得到解决。但我只需要解析恒定值 - 这足以满足我的目的。
谢谢。
编辑:“ToDo”方法(和类似的方法)应该用作注释的替代方法( //, /* ...*/ ),编译后,应该是 IL 分析和自动生成的文档以及具体组装的待办事项列表。
解决方案
代码生成有点令人困惑,但对于简单的情况可以完成:
编译:
public static void Main(string[] args)
{
Console.WriteLine("", // ignore this argument
"Should create array of ", typeof(int), " with specified size." "x");
}
(添加“x”以强制其使用参数重载)
给出
.method public hidebysig static void Main(string[] args) cil managed
{
.custom instance void [mscorlib]System.STAThreadAttribute::.ctor()
.maxstack 4
.locals init (
[0] object[] objArray)
L_0000: ldstr ""
L_0005: ldc.i4.4
L_0006: newarr object
L_000b: stloc.0
L_000c: ldloc.0
L_000d: ldc.i4.0
L_000e: ldstr "Should create array of "
L_0013: stelem.ref
L_0014: ldloc.0
L_0015: ldc.i4.1
L_0016: ldtoken int32
L_001b: call class [mscorlib]System.Type
[mscorlib]System.Type::GetTypeFromHandle(
valuetype [mscorlib]System.RuntimeTypeHandle)
L_0020: stelem.ref
L_0021: ldloc.0
L_0022: ldc.i4.2
L_0023: ldstr " with specified size."
L_0028: stelem.ref
L_0029: ldloc.0
L_002a: ldc.i4.3
L_002b: ldstr "x"
L_0030: stelem.ref
L_0031: ldloc.0
L_0032: call void [mscorlib]System.Console::WriteLine(string, object[])
L_0037: ret
}
因此,您要做的就是解析 il 以检测被推入编译器生成的数组中的参数。这种荒唐的说法很脆弱,但可能足以说明:
- 找到对“我的方法”的调用。
- 查找最近的前一个 newarr 对象
- 获取它们之间的所有 ldstr 和 ldtoken 并假设它们是参数。
这很粗糙,但可能足以满足您的需求。
AOP 风格的方法会让你得到你想要的 运行 通过简单地检测每个调用来转储值,但在简单的时候,上面的方法是仅给出 IL 的唯一现实选择。
生成的代码在发布版本中可能非常不同,您将无法发现自动生成的数组与某人自己显式创建的数组(可能距离调用站点更远,甚至在不同的方法/构造函数/类中)。
附带条款
我应该在编辑后注意到为什么你想要这样做,基于属性的注释是一个更好的解决方案,我不明白为什么当你可以直接属性它时你会想要在方法中这样做......
其他提示
我不知道你的意思。但是,请注意你的函数实际上只得到的一个的说法:一个数组。这是你在IL得到什么了。 在的功能,您可以通过阵列走得到其值:
public static void ToDo( params object[] info ) {
foreach (object x in info)
Console.WriteLine(x);
}
不隶属于 StackOverflow