dotnet 警惕使用 StackTrace 加获取方法标记 Attribute 特性在 Release 下被内联
大家都知道,在 dotnet 里的 Debug 下和 Release 下的一个最大的不同是在 Release 下开启了代码优化。启用代码优化,将会对生成的 IL 代码进行优化,同时优化后的 IL 也会有一些运行时的更多优化。内联是一个非常常用的优化手段,内联将会让 StackTrace 获取的调用堆栈存在 Debug 下和 Release 下的差异,从而导致获取方法标记的 Attribute 特性不能符合预期工作
这一个坑是来源于我所在团队开源的 CUnit (中文单元测试框架) 仓库的一次单元测试过程,我发现了在 Debug 下能通过测试,但是在 Release 下失败。详细请看: https://github.com/dotnet-campus/CUnit/actions/runs/3327386251/jobs/5502313113
核心原因是在 CUnit (中文单元测试框架) 仓库里使用了 StackTrace 的方式获取调用堆栈,通过调用堆栈获取各个方法,找到标记了 TestMethodAttribute 的方法,定位到标记是单元测试的方法
在 Release 下,发现找不到任何一个标记了 TestMethodAttribute 的方法。通过日志输出可以看到在 Debug 下和 Release 下的调用堆栈是不相同的。在 Release 下少了几个方法,刚好这几个方法里面就包含了一个标记了 TestMethodAttribute 的方法
其原因是在 Release 下默认开启了代码优化,在代码优化时,将会尝试内联一些函数,导致了调用堆栈中存在一些函数是看不到的,因为这些函数在实际运行过程中是不存在的,被内联到其他方法里面去了。换句话说,即使不是在 Release 下,只要开启了代码优化,那么都可能因为代码优化让某些函数被内联,从而让调用堆栈看起来不符合预期
因此,使用 StackTrace 获取调用堆栈,将在不同的环境下可能存在一些差异,导致逻辑不符合预期。如果再需要从方法上,获取方法标记的特性,那这个逻辑自然是不靠谱的
规避方法有两个:
第一个,那就是不要这么使用,找找其他的方法
第二个是,如果没有其他的方法,那可以考虑在明确需要获取某个特性的函数上,标记 [MethodImpl(MethodImplOptions.NoInlining)] 表示此函数不要被内联
dotnet 警惕使用 StackTrace 加获取方法标记 Attribute 特性在 Release 下被内联的更多相关文章
- PHP 加解密方法大全
最近看见一篇文章讲的是PHP的加解密方法,正好也自己学习下,顺便以后有用到的地方也好能快速用上,仅供自己学习和复习,好了不多BB,上代码. 基于这几个函数可逆转的加密为:base64_encode() ...
- Linux系统的命令源码的获取方法
我们知道,Linux是开源的,它自带的功能强大的命令也是开源的,也就是说.我们能够获得这些命令的源码并研究它.那到底怎样获得系统的命令的源码呢? 命令的源码是一个软件包为单元的,放在一个软件包的源码中 ...
- Java方法内联
一.概念 方法内联就是把调用方函数代码"复制"到调用方函数中,减少因函数调用开销的技术 函数调用过程 1.首先会有个执行栈,存储它们的局部变量.方法名.动态连接 2.当一个方法 ...
- Java 方法内联
什么是Java 方法内联? 我们先来看看普遍的内联函数含义.在维基百科中解释为: 内联函数:在计算机科学中,内联函数(有时称作在线函数或编译时期展开函数)是一种编程语言结构,用来建议编译器对一些特殊函 ...
- 仅反射加载(ReflectionOnlyLoadFrom)的 .NET 程序集,如何反射获取它的 Attribute 元数据呢?
原文:仅反射加载(ReflectionOnlyLoadFrom)的 .NET 程序集,如何反射获取它的 Attribute 元数据呢? 平时我们获取一个程序集或者类型的 Attribute 是非常轻松 ...
- 先说一下JS的获取方法,其要比JQUERY的方法麻烦很多,后面以JQUERY的方法作对比。
先说一下JS的获取方法,其要比JQUERY的方法麻烦很多,后面以JQUERY的方法作对比. JS的方法会比JQUERY麻烦很多,主要则是因为FF浏览器,FF浏览器会把你的换行也当最DOM元素 复制代码 ...
- <经验杂谈>C#中一种最简单、最基本的反射(Reflection):通过反射获取方法函数
说起反射之前和很多用C#/.net的同仁们一样,相比于一般应用层对数据的增删改查总有点觉得深奥到难以理解.其实程序这东西,用过.实践过就很简单,我一直这么认为. 先说下概念:反射 Reflection ...
- c#图像处理入门(-bitmap类和图像像素值获取方法)
c#图像处理入门 -bitmap类和图像像素值获取方法 一.Bitmap类 Bitmap对象封装了GDI+中的一个位图,此位图由图形图像及其属性的像素数据组成.因此Bitmap是用于处理由像素数据定义 ...
- java 反射机制之 getDeclaredMethod()获取方法,然后invoke执行实例对应的方法
关于反射中getDeclaredMethod().invoke()的学习,来源于项目中的一行代码: SubjectService.class.getDeclaredMethod(autoMatchCo ...
- 【转】StackTraceElement获取方法调用栈的信息
本文链接:https://blog.csdn.net/hp910315/article/details/52702199 一.什么是StackTrace StackTrace(堆栈轨迹)存放的就是方法 ...
随机推荐
- 【Leetcode】63. 不同路径 II
题目(链接) 一个机器人位于一个m x n网格的左上角 (起始点在下图中标记为 "Start" ). 机器人每次只能向下或者向右移动一步.机器人试图达到网格的右下角(在下图中标记为 ...
- 记录--一行代码修复100vh bug
这里给大家分享我在网上总结出来的一些知识,希望对大家有所帮助 你知道奇怪的移动视口错误(也称为100vh bug)吗?或者如何以正确的方式创建全屏块? 一.100vh bug 什么是移动视口错误? 你 ...
- 《.NET内存管理宝典 》(Pro .NET Memory Management) 阅读指南 - 第9章
本章勘误: 暂无,等待细心的你告诉我哦. 本章注解: 暂无 本章释疑: 暂无,等待你的提问 致谢: MVP 林德熙 MVP 吕毅 sPhinX 相关链接 试读记录
- 并发CPU伪共享及优化
伪共享 缓存系统中是以缓存行(cache line)为单位存储的.缓存行是2的整数幂个连续字节,一般为32-256个字节.最常见的缓存行大小是64个字节.当多线程修改互相独立的变量时,如果这些变量共享 ...
- KafkaConsumerDemo
pom <dependency> <groupId>org.springframework.kafka</groupId> <artifactId>sp ...
- C++中结构体的各种用法,详细版
C++中的结构体是一种用户自定义的数据类型,可以存储不同类型的数据成员.以下是一些结构体的常见用法: 1. 定义结构体类型 结构体类型的定义可以放在函数内部或外部,例如: ``` struct Per ...
- Scala 元祖Tuple
1 package chapter07 2 3 object Test10_Tuple { 4 def main(args: Array[String]): Unit = { 5 // 1. 创建元组 ...
- clang的lto特性的资料
clang对lto的支持,如下文章介绍的清晰.易懂. ThinLTO llvm+clang 添加 LTO(Link Time Optimization) 支持 编译优化之 - 链接时优化(LTO)入门 ...
- SpringCloud OpenFeign token中转
OpenFeign 的本质是调用指定服务的 Controller. 前后端分离项目,调用 Controller 是需要传递 token 的. OpenFeign 并不会自动携带 token 去访问 C ...
- MogDB学习笔记之 -- 了解pagewriter线程
MogDB 学习笔记之 -- 了解 pagewriter 线程 本文出处:https://www.modb.pro/db/183172 在前面的 MogDB 学习系列中,我们了解了核心的 bgwrit ...