首页 > 编程语言 >小心C#中的只读结构体成员

小心C#中的只读结构体成员

时间:2023-11-28 16:15:07浏览次数:29  
标签:rcx 只读 C# 小心 Number myStruct int public

示例

  • 我们先来看一段结构体的代码 (基于 VS2022 + .NET 8.0)
public struct MyStruct(int number)
{
    public int Number = number;
    public void SetNumber(int number) => Number = number;
}
public class Program
{
    private static MyStruct myStruct = new(1);
    public static void Main()
    {
        int before = myStruct.Number;
        myStruct.SetNumber(2);
        int after = myStruct.Number;
        Console.WriteLine($"before: {before}");
        Console.WriteLine($" after: {after}");
        Console.ReadKey();
    }
}

输出如下:
before: 1
 after: 2

修改为只读

  • private static readonly MyStruct myStruct = new(1);

输出如下:
before: 1
 after: 1

  • 我们看到,修改只读结构体成员的字段失败了,但是编译器竟然没有报错
  • 如果我们直接操作 myStruct.Number = 2; 编译器是会报错的,但是加了一个方法间接的修改,编译器就歇菜了

内部原理

我们查看反汇编代码,可以看到,在实际操作只读结构体成员字段的时候,会把该字段的值拷贝一份到一个新的堆栈变量上,然后再基于拷贝后的这个变量计算

    17:         myStruct.SetNumber(2);
 mov         rcx,7FF9BD68E500h
 mov         edx,9
 call        CORINFO_HELP_GETSHARED_NONGCSTATIC_BASE (07FFA1D15B6F0h)
 mov         rcx,26AE19DB1D0h         //rcx保存结构体Number的地址
 mov         rcx,qword ptr [rcx]      //拷贝Number的值到rcx
 mov         qword ptr [rbp+70h],rcx  //rcx的值赋值到临时变量
 lea         rcx,[rbp+70h]
 mov         edx,2
 call        ConsoleTest_NET_8.MyStruct.SetNumber(Int32) (07FF9BD6A2BC8h)

导致的问题

  • 我们先来看一段自旋锁的代码,基于 SpinLock
public class Program
{
    private static readonly SpinLock spinLock = new(false);
    public static void Main()
    {
        int sum = 0;
        Parallel.For(0, ushort.MaxValue, i =>
        {
            bool lockToken = false;
            try
            {
                spinLock.Enter(ref lockToken);
                sum++;
            }
            finally
            {
                if (lockToken)
                {
                    spinLock.Exit();
                }
            }
        });
        Console.WriteLine(sum);
        Console.ReadKey();
    }
}
  • 我们期望的输出是: 65535, 但实际不是,因为隐藏的只读机制导致了字段值的拷贝, 这就造成了隐藏的 BUG

结论

  • 避免把结构体成员变量设置只读

  • 在确定结构体内的字段只读时,可以使用 readonly 直接修饰 结构体本身或者字段,比如

    public readonly struct MyStruct(int number)
    {
        public readonly int Number = number;
    }
    

标签:rcx,只读,C#,小心,Number,myStruct,int,public
From: https://www.cnblogs.com/broadm/p/17862169.html

相关文章

  • 【OpenGauss】CentOS安装
    【OpenGauss】CentOS安装1、关闭防火墙修改vim/etc/selinux/configSELINUX=disabled#禁止自动启动systemctldisablefirewalld.service#停止防火请systemctlstopfirewalld.service#重启系统reboot#查看状态systemctlstatusfirewalld ......
  • 世微 舞台灯车灯深度调光大功率 降压恒流驱动IC APS54083
    产品描述      APS54083是一款PWM工作模式,高效率、外围简单、外置功率MOS管,适用于5-220V输入高精度降压LED恒流驱动芯片。输出最大功率150W最大电流6A。APS54083可实现线性调光和PWM调光,线性调光脚有效电压范围0.5-2.5V.PWM调光频率范围100HZ-30KHZ......
  • Oracle Database 19c 创建只读用户
    1.登录oracle数据库服务器,以管理员用户登录sqlplus/assysdba切换容器等操作showpdbs; altersessionsetcontainer=ORA19CPDB;showcon_name;2.创建只读用户createusercmsreadonlyidentifiedbycmsreadonlydefaulttablespaceCMSPROD_DATA......
  • Oracle临时表会随另外一个表的创建自动提交并清空
    创建一个临时表,用它导入一些数据用这个临时表生成另外一个表,用createtable...但生成的这表总是空的。原来createtable前会进行提交commit,而临时表在commit时会自动清空(默认属性,可以改)所以生成的表总是空的。这种情况下就不要用临时表了,用普通表,因为反正用完是要手工删......
  • SP19543 GSS8 - Can you answer these queries VIII 题解
    更好的阅读体验SP19543GSS8-CanyouanswerthesequeriesVIIIfhq+二项式定理。提供一个不太一样的思路。默认下标从\(1\)开始。首先插入删除,区间查询,想到可以平衡树维护或者离线下来做线段树。本文中是用的是fhq,好写一些。\(k\)非常的小,考虑对于每一个\(k\)的答......
  • linux:systemd 禁用ctrl-alt-del:centos、rhel、fedora、ubuntu
     systemctlstatusctrl-alt-del.target;systemctlmaskctrl-alt-del.target;systemctlstatusctrl-alt-del.target;history-csystemctlstatusctrl-alt-del.target;systemctlmaskctrl-alt-del.target;systemctlstatusctrl-alt-del.target;history-c......
  • 《Visual Analytics for RNN-Based Deep Reinforcement Learning》
    摘要准备开题报告,整理一篇2022年TOP论文。论文介绍该论文是一篇2022年,有关可视化分析基于RNN的深度强化学习训练过程的文章。一作是JunpengWang,作者主要研究领域就是:visualization,visualanalytics,explainableAI。作者主页:https://junpengw.github.io/#/主要工......
  • Failed to instantiate [com.zaxxer.hikari.HikariDataSource]
    问题描述  明明在yml文件里配置了相关数据库,怎么仍启动报错?这个hikari又是什么?  问题解决  排除springboot默认的数据库自动装配  ......
  • 关于 FontAwesome 字体图标库的 content 属性
    下图这个例子里,\f0002被映射为一个放大镜图标:代码:.fa-search:before{content:"\f002";}在Web前端开发中,上图提到的代码是属于使用字体图标(iconfonts)的一种方式。在这个特定的例子中,.fa-search是一个CSS类,:before是一个伪元素选择器,用于在匹配的元素前插入内容。而co......
  • Can Pre-Trained Text-to-Image Models Generate Visual Goals for Reinforcement Lea
    概述LearningformtheVoid(LfVoid)根据给定的languageinstruction对observation进行appearance-basedandstructure-based修改得到goalimages,为RL提供奖励信号。提升了example-basedRLmethods,无需rewardfunction或者demonstration就可以解决一些robotcontroltasks问......