日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當(dāng)前位置: 首頁 > 编程语言 > C# >内容正文

C#

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

發(fā)布時間:2023/11/29 C# 52 coder
生活随笔 收集整理的這篇文章主要介紹了 小心C#中的只读结构体成员 小編覺得挺不錯的,現(xiàn)在分享給大家,幫大家做個參考.

示例

  • 我們先來看一段結(jié)構(gòu)體的代碼 (基于 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

  • 我們看到,修改只讀結(jié)構(gòu)體成員的字段失敗了,但是編譯器竟然沒有報錯
  • 如果我們直接操作 myStruct.Number = 2; 編譯器是會報錯的,但是加了一個方法間接的修改,編譯器就歇菜了

內(nèi)部原理

我們查看反匯編代碼,可以看到,在實際操作只讀結(jié)構(gòu)體成員字段的時候,會把該字段的值拷貝一份到一個新的堆棧變量上,然后再基于拷貝后的這個變量計算

    17:         myStruct.SetNumber(2);
 mov         rcx,7FF9BD68E500h
 mov         edx,9
 call        CORINFO_HELP_GETSHARED_NONGCSTATIC_BASE (07FFA1D15B6F0h)
 mov         rcx,26AE19DB1D0h         //rcx保存結(jié)構(gòu)體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)

導(dǎo)致的問題

  • 我們先來看一段自旋鎖的代碼,基于 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, 但實際不是,因為隱藏的只讀機制導(dǎo)致了字段值的拷貝, 這就造成了隱藏的 BUG

結(jié)論

  • 避免把結(jié)構(gòu)體成員變量設(shè)置只讀

  • 在確定結(jié)構(gòu)體內(nèi)的字段只讀時,可以使用 readonly 直接修飾 結(jié)構(gòu)體本身或者字段,比如

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

總結(jié)

以上是生活随笔為你收集整理的小心C#中的只读结构体成员的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網(wǎng)站內(nèi)容還不錯,歡迎將生活随笔推薦給好友。