欢迎访问 生活随笔!

凯发k8官方网

当前位置: 凯发k8官方网 > 编程语言 > c# >内容正文

c#

小心c#中的只读结构体成员 -凯发k8官方网

发布时间:2023/11/29 c# 27 coder
凯发k8官方网 收集整理的这篇文章主要介绍了 小心c#中的只读结构体成员 小编觉得挺不错的,现在分享给大家,帮大家做个参考.

示例

  • 我们先来看一段结构体的代码 (基于 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;
    }
    

总结

以上是凯发k8官方网为你收集整理的小心c#中的只读结构体成员的全部内容,希望文章能够帮你解决所遇到的问题。

如果觉得凯发k8官方网网站内容还不错,欢迎将凯发k8官方网推荐给好友。

  • 上一篇:
  • 下一篇:
网站地图