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(堆栈轨迹)存放的就是方法 ...
随机推荐
- Android组件化开发实践和案例分享
目录介绍 1.为什么要组件化 1.1 为什么要组件化 1.2 现阶段遇到的问题 2.组件化的概念 2.1 什么是组件化 2.2 区分模块化与组件化 2.3 组件化优势好处 2.4 区分组件化和插件化 ...
- ElasticSearch8 - SpringBoot整合ElasticSearch
前言 springboot 整合 ES 有两种方案,ES 官方提供的 Elasticsearch Java API Client 和 spring 提供的 [Spring Data Elasticse ...
- IDEA 突然无法打开 解决办法
如果实在没有方法了可以试一试 删除所有的配置文件,默认位置C:\Users\${你的用户名}\${.IntelliJIdea+版本} 注意:删除配置后之前所有的设置都会失效,谨慎操作.
- C# 人脸检测 人脸比对 活体检测 口罩检测 年龄预测 性别预测 眼睛状态检测
基于以下开源软件做了一个Demo GitHub - ViewFaceCore/ViewFaceCore: C# 超简单的离线人脸识别库.( 基于 SeetaFace6 ) 效果 代码 using Sy ...
- [ROS串口通信]报错:IO Exception (13): Permission denied, file /tmp/binarydeb/ros-noetic-serial-1.2.1/src/impl/unix.cc, line 151. [ERROR] [1705845384.528602780]: Unable to open port
ROS在串口通信时,当我们插入USB后,catkin_make之后,报错: IO Exception (13): Permission denied, file /tmp/binarydeb/ros- ...
- C# 金额的 动态分配算法
/// <summary> /// 金额的 动态分配算法 /// </summary> public static void FindCosts() { // 定义费用明细列表 ...
- #KD-Tree,替罪羊树#洛谷 6224 [BJWC2014]数据
题目 平面上有 \(N\) 个点.需要实现以下三种操作: 在点集里添加一个点: 给出一个点,查询它到点集里所有点的曼哈顿距离的最小值: 给出一个点,查询它到点集里所有点的曼哈顿距离的最大值. 分析 用 ...
- #差分约束系统,Spfa,SLF优化#HDU 3666 THE MATRIX PROBLEM
题目 多组询问,给定一个\(n*m\)的矩阵\(C\)和一个区间\([L,R]\), 问是否存在一个长度为\(n\)的序列\(A\)和一个长度为\(m\)的序列\(B\), 使得所有 \[\frac{ ...
- 为什么 L1 正则化能做特征选择而 L2 正则化不能
假设我们的模型只有一个参数 \(w\),损失函数为 \(L(w)\),加入 L1 和 L2 正则化后的损失函数分别记为 \(J_1(w), J_2(w)\): \[\begin{gathered} J ...
- Go 语言注释教程
注释是在执行时被忽略的文本.注释可用于解释代码,使其更易读.注释还可用于在测试替代代码时防止代码执行.Go支持单行或多行注释. Go单行注释 单行注释以两个正斜杠(//)开头. 在//和行尾之间的任何 ...