如何通过反射从已编译C#类中提取ToString方法的表达式?
解答
可以通过解析方法的IL代码提取到你需要的信息,甚至可以直接反编译出完整的方法体字符串,完全满足需求。
- 首先你写的表达式体
ToString方法里的插值字符串,C#编译器默认会编译为string.Format调用,你示例中的代码编译后等价于:
public override string ToString() { return string.Format("{0}, {1}", this.LastName, this.FirstName); }
所有常量、属性调用的信息都完整保存在IL和程序集元数据中。
- 原生反射实现方案:
拿到MethodInfo对象后调用GetMethodBody(),再调用GetILAsByteArray()获取原始IL字节流,按如下步骤解析即可:
- 遍历IL指令,找到
call指令对应的string.Format方法元数据 - 从元数据常量池读取
Format方法的第一个参数,也就是格式化字符串模板"{0}, {1}" - 依次读取后续参数的调用指令,提取出对应的
LastName、FirstName属性信息 - 把模板中的占位符和属性名对应替换,即可还原出你要的
"${LastName}, {FirstName}"格式结果
- 更简单的替代方案:
不需要自己手动解析IL,直接集成ICSharpCode.Decompiler(ILSpy的核心反编译库),几行代码就能直接拿到方法的C#源码字符串,示例代码如下:
var assembly = Assembly.GetAssembly(typeof(Person)); var resolver = new UniversalAssemblyResolver(assembly.Location, false, assembly.GetName().Version.ToString()); var decompiler = new CSharpDecompiler(assembly.Location, resolver, new DecompilerSettings()); var methodInfo = typeof(Person).GetMethod("ToString"); var methodCode = decompiler.Decompile(methodInfo.MetadataToken).ToString(); // 输出的methodCode就包含完整的ToString方法源码,直接提取表达式部分即可
- 注意事项:如果方法体逻辑更复杂,或者开启了高度优化的编译选项,IL解析的复杂度会明显提升,优先用成熟的反编译库处理更稳妥。
内容的提问来源于stack exchange,提问作者Andreas Zita
相关产品推荐
相关产品推荐

