经验首页 前端设计 程序设计 Java相关 移动开发 数据库/运维 软件/图像 大数据/云计算 其他经验
当前位置:技术经验 » 程序设计 » C# » 查看文章
小心C#中的只读结构体成员
来源:cnblogs  作者:Broadm  时间:2023/11/29 16:17:56  对本文有异议

示例

  • 我们先来看一段结构体的代码 (基于 VS2022 + .NET 8.0)
  1. public struct MyStruct(int number)
  2. {
  3. public int Number = number;
  4. public void SetNumber(int number) => Number = number;
  5. }
  6. public class Program
  7. {
  8. private static MyStruct myStruct = new(1);
  9. public static void Main()
  10. {
  11. int before = myStruct.Number;
  12. myStruct.SetNumber(2);
  13. int after = myStruct.Number;
  14. Console.WriteLine($"before: {before}");
  15. Console.WriteLine($" after: {after}");
  16. Console.ReadKey();
  17. }
  18. }

输出如下:
before: 1
?after: 2

修改为只读

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

输出如下:
before: 1
?after: 1

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

内部原理

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

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

导致的问题

  • 我们先来看一段自旋锁的代码,基于 SpinLock
  1. public class Program
  2. {
  3. private static readonly SpinLock spinLock = new(false);
  4. public static void Main()
  5. {
  6. int sum = 0;
  7. Parallel.For(0, ushort.MaxValue, i =>
  8. {
  9. bool lockToken = false;
  10. try
  11. {
  12. spinLock.Enter(ref lockToken);
  13. sum++;
  14. }
  15. finally
  16. {
  17. if (lockToken)
  18. {
  19. spinLock.Exit();
  20. }
  21. }
  22. });
  23. Console.WriteLine(sum);
  24. Console.ReadKey();
  25. }
  26. }
  • 我们期望的输出是: 65535, 但实际不是,因为隐藏的只读机制导致了字段值的拷贝, 这就造成了隐藏的 BUG

结论

  • 警惕把结构体成员变量设置只读

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

    1. public readonly struct MyStruct(int number)
    2. {
    3. public readonly int Number = number;
    4. }

原文链接:https://www.cnblogs.com/broadm/p/17862169.html

 友情链接:直通硅谷  点职佳  北美留学生论坛

本站QQ群:前端 618073944 | Java 606181507 | Python 626812652 | C/C++ 612253063 | 微信 634508462 | 苹果 692586424 | C#/.net 182808419 | PHP 305140648 | 运维 608723728

W3xue 的所有内容仅供测试,对任何法律问题及风险不承担任何责任。通过使用本站内容随之而来的风险与本站无关。
关于我们  |  意见建议  |  捐助我们  |  报错有奖  |  广告合作、友情链接(目前9元/月)请联系QQ:27243702 沸活量
皖ICP备17017327号-2 皖公网安备34020702000426号