<output id="qn6qe"></output>

    1. <output id="qn6qe"><tt id="qn6qe"></tt></output>
    2. <strike id="qn6qe"></strike>

      亚洲 日本 欧洲 欧美 视频,日韩中文字幕有码av,一本一道av中文字幕无码,国产线播放免费人成视频播放,人妻少妇偷人无码视频,日夜啪啪一区二区三区,国产尤物精品自在拍视频首页,久热这里只有精品12

      提高 C# 的生產力:C# 13 更新完全指南

      前言

      預計在 2024 年 11 月,C# 13 將與 .NET 9 一起正式發布。今年的 C# 更新主要集中在 ref struct 上進行了許多改進,并添加了許多有助于進一步提高生產力的便利功能。

      本文將介紹預計將在 C# 13 中添加的功能。

      注意:目前 C# 13 還未正式發布,因此以下內容可能會發生變化。

      在迭代器和異步方法中使用 refref struct

      在使用 C# 進行編程時,你是否經常使用 ref 變量和 Spanref struct 類型?然而,這些不能在迭代器和異步方法中使用,于是必須使用局部函數等來避免在迭代器和異步方法中直接使用 ref 變量 ref struct 類型,這非常不方便。

      這個缺點在 C# 13 中得到了改善,現在迭代器和異步方法也可以使用 refref struct 了!

      在迭代器中使用 refref struct 的例子:

      IEnumerable<float> GetFloatNumberFromIntArray(int[] array)
      {
          for (int i = 0; i < array.Length; i++)
          {
              Span<int> span = array.AsSpan();
              // 進行一些處理...
              ref float v = ref Unsafe.As<int, float>(ref array[i]);
              yield return v;
          }
      }
      

      在異步方法中使用 ref struct 的例子:

      async Task ProcessDataAsync(int[] array)
      {
          Span<int> span = array.AsSpan();
          // 進行一些處理...
          ref int element = ref span[42];
          element++;
          await Task.Yield();
      }
      

      為了展示功能,我使用了不適當且含糊不清的“一些處理”,不過重要的是現在可以使用 refref struct 了!

      但是,有一點需要注意,ref 變量和 ref struct 類型的變量不能超出 yieldawait 的邊界使用。例如,以下示例將導致編譯錯誤。

      async Task ProcessDataAsync(int[] array)
      {
          Span<int> span = array.AsSpan();
          // 進行一些處理...
          ref int element = ref span[42];
          element++;
          await Task.Yield();
          element++; // 錯誤:對 element 的訪問超出了 await 的邊界
      }
      

      雖然我們已經說到這里,但我想可能有人會疑惑,到底 refref struct 是什么,所以我稍微解釋一下。

      在 C# 中,可以使用 ref 來獲取變量的引用。這樣,就可以通過引用來更改原始變量。以下是一個例子:

      void Swap(ref int a, ref int b) // ref 表示引用
      {
          int temp = a;
          a = b;
          b = temp; // 到這里,a 和 b 已經交換了
      }
      
      int x = 1;
      int y = 2;
      Swap(ref x, ref y); // 獲取 x 和 y 的引用,調用 Swap 來交換 x 和 y
      

      另一方面,ref struct 是用于定義只能存在于堆棧上的值類型的。這是為了避免垃圾收集的開銷。然而,由于 ref struct 只能存在于堆棧上,所以在 C# 13 之前,它不能在迭代器和異步方法等地方使用。

      順便一提,ref struct 之所以帶有 ref,是因為 ref struct 的實例只能存在于堆棧上,其遵循的生命周期規則與 ref 變量相同。

      allows ref struct 泛型約束

      在以前,ref struct 不能作為泛型類型參數使用,因此,考慮到代碼的可重用性,引入了泛型,但最終 ref struct 不能使用,必須為 SpanReadOnlySpan 重新編寫相同的處理,于是就很麻煩。

      在 C# 13 中,泛型類型也可以使用 ref struct 了:

      using System;
      using System.Numerics;
      
      Process([1, 2, 3, 4], Sum); // 10
      Process([1, 2, 3, 4], Multiply); // 24
      
      T Process<T>(ReadOnlySpan<T> span, Func<ReadOnlySpan<T>, T> method)
      {
          return method(span);
      }
      
      T Sum<T>(ReadOnlySpan<T> span) where T : INumberBase<T>
      {
          T result = T.Zero;
          foreach (T value in span)
          {
              result += value;
          }
          return result;
      }
      
      T Multiply<T>(ReadOnlySpan<T> span) where T : INumberBase<T>
      {
          T result = T.One;
          foreach (T value in span)
          {
              result *= value;
          }
          return result;
      }
      

      為什么像 ReadOnlySpan<T> 這樣的 ref struct 類型可以作為 Func 的類型參數呢?為了調查這個問題,我查看了 .NET 的 源代碼,發現 Func 類型的泛型參數是這樣定義的:

      public delegate TResult Func<in T, out TResult>(T arg)
          where T : allows ref struct
          where TResult : allows ref struct;
      

      如果在泛型參數上添加 allow ref struct 約束,那么就可以將 ref struct 類型傳遞給該參數。

      這確實是一個方便的功能。

      ref struct 也可以實現接口

      在 C# 13 中,ref struct 可以實現接口。

      如果將此功能與 allows ref struct 結合使用,那么也可以通過泛型類型傳遞引用:

      using System;
      using System.Numerics;
      
      int a = 10;
      // 使用 Ref<int> 保存 a 的引用
      Ref<int> aRef = new Ref<int>(ref a);
      // 傳遞 Ref<int>
      Increase<Ref<int>, int>(aRef);
      Console.WriteLine(a); // 11
      
      void Increase<T, U>(T data) where T : IRef<U>, allows ref struct where U : INumberBase<U>
      {
          ref U value = ref data.GetRef();
          value++;
      }
      
      interface IRef<T>
      {
          ref T GetRef();
      }
      
      // 為 Ref<T> 這樣的 ref struct 實現接口
      ref struct Ref<T> : IRef<T>
      {
          private ref T _value;
      
          public Ref(ref T value)
          {
              _value = ref value;
          }
      
          public ref T GetRef()
          {
              return ref _value;
          }
      }
      

      這樣一來,編寫 ref struct 相關的代碼就變得更容易了。另外,也能給各種 ref struct 實現的枚舉器實現 IEnumerator 之類的接口了。

      集合類型和 Span 也可以使用 params

      在以前,params 只能用于數組類型,但從 C# 13 開始,它也可以用于其他集合類型和 Span

      params 是一種功能,允許在調用方法時直接指定任意數量的參數。

      例如,

      Test(1, 2, 3, 4, 5, 6);
      void Test(params int[] values) { }
      

      如上所示,可以直接指定任意數量的 int 參數。

      從 C# 13 開始,除了數組類型外,其他集合類型、SpanReadOnlySpan 類型以及與集合相關的接口也可以添加 params

      Test(1, 2, 3, 4, 5, 6);
      void Test(params ReadOnlySpan<int> values) { }
      
      // 或者
      Test(1, 2, 3, 4, 5, 6);
      void Test(params List<int> values) { }
      
      // 接口也可以
      Test(1, 2, 3, 4, 5, 6);
      void Test(params IEnumerable<int> values) { }
      

      這也很方便!

      field 關鍵字

      在實現 C# 的屬性時,經常需要定義一大堆字段,如下所示...

      partial class ViewModel : INotifyPropertyChanged
      {
          // 定義字段
          private int _myProperty;
      
          public int MyProperty
          {
              get => _myProperty;
              set
              {
                  if (_myProperty != value)
                  {
                      _myProperty = value;
                      OnPropertyChanged();
                  }
              }
          }
      }
      

      因此,從 C# 13 開始,field 關鍵字將派上用場!

      partial class ViewModel : INotifyPropertyChanged
      {
          public int MyProperty
          {
              // 只需使用 field
              get => field;
              set
              {
                  if (field != value)
                  {
                      field = value;
                      OnPropertyChanged();
                  }
              }
          }
      }
      

      不再需要自己定義字段,只需使用 field 關鍵字,字段就會自動生成。

      這也非常方便!

      部分屬性

      在編寫 C# 時,常見的問題之一是:屬性不能添加 partial 修飾符。

      在 C# 中,可以在類或方法上添加 partial,以便分別進行聲明和實現。此外,還可以分散類的各個部分。它的主要用途是在使用源代碼生成器等自動生成工具時,指定要生成的內容。

      例如:

      partial class ViewModel
      {
          // 這里只聲明方法,實現部分由工具自動生成
          partial void OnPropertyChanged(string propertyName);
      }
      

      然后自動生成工具會生成以下代碼:

      partial class ViewModel : INotifyPropertyChanged
      {
          public event PropertyChangedEventHandler? PropertyChanged;
      
          partial void OnPropertyChanged(string propertyName)
          {
              PropertyChanged?.Invoke(this, new(propertyName));
          }
      }
      

      開發者只需要聲明 OnPropertyChanged,其實現將全部由自動生成,從而節省了開發者的時間。

      從 C# 13 開始,屬性也支持 partial

      partial class ViewModel
      {
          // 聲明部分屬性
          public partial int MyProperty { get; set; }
      }
      
      partial class ViewModel
      {
          // 部分屬性的實現
          public partial int MyProperty
          {
              get
              {
                  // ...
              }
              set
              {
                  // ...
              }
          }
      }
      

      這樣,屬性也可以由工具自動生成了。

      鎖對象

      眾所周知,lock 是一種功能,通過監視器用于線程同步。

      object lockObject = new object();
      lock (lockObject)
      {
          // 關鍵區
      }
      

      但是,這個功能的開銷其實很大,會影響性能。

      為了解決這個問題,C# 13 實現了鎖對象。要使用此功能,只需用 System.Threading.Lock 替換被鎖定的對象即可:

      using System.Threading;
      
      Lock lockObject = new Lock();
      lock (lockObject)
      {
          // 關鍵區
      }
      

      這樣就可以輕松提高性能了。

      初始化器中的尾部索引

      索引運算符 ^ 可用于表示集合末尾的相對位置。從 C# 13 開始,初始化器也支持此功能:

      var x = new Numbers
      {
          Values = 
          {
              [1] = 111,
              [^1] = 999 // ^1 是從末尾開始的第一個元素
          }
          // x.Values[1] 是 111
          // x.Values[9] 是 999,因為 Values[9] 是最后一個元素
      };
      
      class Numbers
      {
          public int[] Values { get; set; } = new int[10];
      }
      

      ESCAPE 字符

      在 Unicode 字符串中,可以使用 \e 代替 \u001b\x1b\u001b\x1b\e 都表示 ESCAPE 字符。它們通常用于表示控制字符。

      • \u001b 表示 Unicode 轉義序列,\u 后面的 4 位十六進制數表示 Unicode 代碼點
      • \x1b 表示十六進制轉義序列,\x 后面的 2 位十六進制數表示 ASCII 代碼
      • \e 表示 ESCAPE 字符本身

      推薦使用 \e 的原因是,可以避免在十六進制中的混淆。

      例如,如果 \x1b 后面跟著 3,則變為 \x1b3,由于 \x1b3 之間沒有明確的分隔,因此不清楚應該分別解釋成 \x1b3,還是放在一起解釋。

      如果使用 \e,則可以避免混淆。

      其他

      除了上述功能外,方法組中的自然類型和方法重載中的優先級也有一些改進,但在本文中省略。如果想了解更多信息,請參閱文檔。

      結語

      C# 正在年復一年地進化,對我來說 C# 13 的更新中實現了許多非常實用且方便的功能,解決了不少實際的痛點。期待 .NET 9 和 C# 13 的正式發布~

      posted @ 2024-07-27 01:16  hez2010  閱讀(4617)  評論(11)    收藏  舉報
      主站蜘蛛池模板: 毛片免费观看视频| 在线中文字幕国产一区| 国产偷国产偷亚洲高清日韩| 97精品尹人久久大香线蕉| 国内精品久久久久电影院| 国内不卡的一区二区三区| 做暖暖视频在线看片免费| 在线免费成人亚洲av| 高中女无套中出17p| 综合色一色综合久久网| 欧美极品色午夜在线视频| 人妻少妇精品中文字幕| 国产女人18毛片水真多1| 加勒比无码人妻东京热| 午夜欧美精品久久久久久久 | 天堂a无码a无线孕交| 一日本道伊人久久综合影| 同心县| 日韩成人高精品一区二区| 国产在线播放专区av| 桃花岛亚洲成在人线AV| 中文字幕99国产精品| 国产午夜福利小视频合集| 日韩av综合免费在线| 亚洲特黄色片一区二区三区| 99热精品国产三级在线观看| 欧美黑人巨大xxxxx| 亚洲国内精品一区二区| 忘忧草日本在线播放www| 国产精品小粉嫩在线观看| 亚洲人成网站18禁止无码| 日韩精品一区二区都可以| 国产av剧情md精品麻豆| 亚洲天堂一区二区成人在线| 国产又色又爽又黄的在线观看| 久久精品国产99国产精品严洲| 精品一区二区无码免费| 亚欧洲乱码视频在线专区| 日本激情久久精品人妻热| 精品无码国产日韩制服丝袜| 蜜臀av无码一区二区三区|