<kbd id="afajh"><form id="afajh"></form></kbd>
<strong id="afajh"><dl id="afajh"></dl></strong>
    <del id="afajh"><form id="afajh"></form></del>
        1. <th id="afajh"><progress id="afajh"></progress></th>
          <b id="afajh"><abbr id="afajh"></abbr></b>
          <th id="afajh"><progress id="afajh"></progress></th>

          C# 10 完整特性介紹

          共 7889字,需瀏覽 16分鐘

           ·

          2021-08-21 02:41


          前言


          開頭防杠:.NET 的基礎(chǔ)庫、語言、運行時團隊從來都是相互獨立各自更新的,.NET 6 在基礎(chǔ)庫、運行時上同樣做了非常多的改進,不過本文僅僅介紹語言部分。


          距離上次介紹 C# 10 的特性已經(jīng)有一段時間了,伴隨著 .NET 6 的開發(fā)進入尾聲,C# 10 最終的特性也終于敲定了。總的來說 C# 10 的更新內(nèi)容很多,并且對類型系統(tǒng)做了不小的改動,解決了非常多現(xiàn)有的痛點。


          從 C# 10 可以看到一個消息,那就是 C# 語言團隊開始主要著重于改進類型系統(tǒng)和功能性方面的東西,而不是像以前那樣熱衷于各種語法糖了。


          C# 10 只是這個旅程的開頭,后面的 C# 11 、12 將會有更多關(guān)于類型系統(tǒng)的改進,使其擁有強如 Haskell 、Rust 的表達能力,不僅能提供從頭到尾的跨程序集的靜態(tài)類型支持,還能做到像動態(tài)類型語言那樣的靈活。


          邏輯代碼是類型的證明,只有類型系統(tǒng)強大了,代碼編寫起來才能更順暢、更不容易出錯。


          record struct


          首先自然是 record struct,解決了 record 只能給 class 而不能給 struct 用的問題:

          record struct Point(int X, int Y);

          用 record 定義 struct 的好處其實有很多,例如你無需重寫 GetHashCodeEquals 之類的方法了。

          sealed record ToString 方法

          之前 record 的 ToString 是不能修飾為 sealed 的,因此如果你繼承了一個 record,相應(yīng)的 ToString 行為也會被改變,因此這是個虛方法。

          但是現(xiàn)在你可以把 record 里的 ToString 方法標(biāo)記成 sealed,這樣你的 ToString 方法就不會被重寫了。

          struct 無參構(gòu)造函數(shù)

          一直以來 struct 不支持無參構(gòu)造函數(shù),現(xiàn)在支持了:

          struct Foo
          {
              public int X;
              public Foo() { X = 1; }
          }

          但是使用的時候就要注意了,因為無參構(gòu)造函數(shù)的存在使得 new struct()default(struct) 的語義不一樣了,例如 new Foo().X == default(Foo).X 在上面這個例子中將會得出 false

          匿名對象的 with

          可以用 with 來根據(jù)已有的匿名對象創(chuàng)建新的匿名對象了:

          var x = new { A = 1, B = 2 };
          var y = x with { A = 3 };

          這里 y.A 將會是 3 。

          局的 using

          利用全局 using 可以給整個項目啟用 usings,不再需要每個文件都寫一份。比如你可以創(chuàng)建一個 Import.cs,然后里面寫:

          using System;
          using i32 = System.Int32;

          然后你整個項目都無需再 using System,并且可以用 i32 了。

          文件范圍的 namespace

          這個比較簡單,以前寫 namespace 還得帶一層大括號,以后如果一個文件里只有一個 namespace 的話,那直接在最上面這樣寫就行了:

          namespace MyNamespace;

          常量字符串插值

          你可以給 const string 使用字符串插值了,非常方便:

          const string x = "hello";
          const string y = $"{x}, world!";

          lambda 改進

          這個改進可以說是非常大,我分多點介紹。

          1、支持 attributes

          lambda 可以帶 attribute 了:

          f = [Foo] (x) => x; // 給 lambda 設(shè)置
          f = [return: Foo] (x) => x; // 給 lambda 返回值設(shè)置
          f = ([Foo] x) => x; // 給 lambda 參數(shù)設(shè)置

          2、支持指定返回值類型

          此前 C# 的 lambda 返回值類型靠推導(dǎo),C# 10 開始允許在參數(shù)列表最前面顯示指定 lambda 類型了:

          f = int () => 4;

          3、支持 ref 、in 、out 等修飾

          f = ref int (ref int x) => ref x; // 返回一個參數(shù)的引用

          4、頭等函數(shù)

          函數(shù)可以隱式轉(zhuǎn)換到 delegate,于是函數(shù)上升至頭等函數(shù):

          void Foo() { Console.WriteLine("hello"); }
          var x = Foo;
          x(); // hello

          5、自然委托類型

          lambda 現(xiàn)在會自動創(chuàng)建自然委托類型,于是不再需要寫出類型了。

          var f = () => 1// Func<int>
          var g = string (int x, string y) => $"{y}{x}"// Func<int, string, string>
          var h = "test".GetHashCode; // Func<int>

          CallerArgumentExpression

          現(xiàn)在,CallerArgumentExpression 這個 attribute 終于有用了。借助這個 attribute,編譯器會自動填充調(diào)用參數(shù)的表達式字符串,例如:

          void Foo(int value, [CallerArgumentExpression("value")] string? expression = null)
          {
              Console.WriteLine(expression + " = " + value);
          }

          當(dāng)你調(diào)用 Foo(4 + 5) 時,會輸出 4 + 5 = 9。這對測試框架極其有用,因為你可以輸出 assert 的原表達式了:

          static void Assert(bool value, [CallerArgumentExpression("value")] string? expr = null)
          {
              if (!valuethrow new AssertFailureException(expr);
          }

          tuple 支持混合定義和使用

          比如:

          int y = 0;
          (var x, y, var z) = (123);

          于是 y 就變成 2 了,同時還創(chuàng)建了兩個變量 x 和 z,分別是 1 和 3 。

          接口支持抽象靜態(tài)方法

          這個特性將會在 .NET 6 作為 preview 特性放出,意味著默認是不啟用的,需要設(shè)置 <LangVersion>preview</LangVersion><EnablePreviewFeatures>true</EnablePreviewFeatures>,然后引入一個官方的 nuget 包 System.Runtime.Experimental 來啟用。

          然后接口就可以聲明抽象靜態(tài)成員了,.NET 的類型系統(tǒng)正式具備虛靜態(tài)方法分發(fā)能力。

          例如,你想定義一個可加而且有零的接口 IMonoid<T>

          interface IMonoid<Twhere T : IMonoid<T>
          {
              abstract static T Zero { get; }
              abstract static T operator+(T l, T r);
          }

          然后可以對其進行實現(xiàn),例如這里的 MyInt:

          public class MyInt : IMonoid<MyInt>
          {
              public MyInt(int val) { Value = val; }

              public static MyInt Zero { get; } = new MyInt(0);
              public static MyInt operator+(MyInt l, MyInt r) => new MyInt(l.Value + r.Value);

              public int Value { get; }
          }

          然后就能寫出一個方法對 IMoniod<T> 進行求和了,這里為了方便寫成擴展方法:

          public static class IMonoidExtensions
          {
              public static T Sum<T>(this IEnumerable<T> t) where T : IMonoid<T>
              {
                  var result = T.Zero;
                  foreach (var i in t) result += i;
                  return result;
              }
          }

          最后調(diào)用:

          List<MyInt> list = new() { new(1), new(2), new(3) };
          Console.WriteLine(list.Sum().Value); // 6

          你可能會問為什么要引入一個 System.Runtime.Experimental,因為這個包里面包含了 .NET 基礎(chǔ)類型的改進:給所有的基礎(chǔ)類型都實現(xiàn)了相應(yīng)的接口,比如給數(shù)值類型都實現(xiàn)了 INumber<T>,給可以加的東西都實現(xiàn)了 IAdditionOperators<TLeft, TRight, TResult> 等等,用起來將會非常方便,比如你想寫一個函數(shù),這個函數(shù)用來把能相加的東西加起來:

          T Add<T>(T left, T right) where T : IAdditionOperators<T, T, T>
          {
              return left + right;
          }

          就搞定了。

          接口的靜態(tài)抽象方法支持和未來 C# 將會加入的 shape 特性是相輔相成的,屆時 C# 將利用 interface 和 shape 支持 Haskell 的 class、Rust 的 trait 那樣的 type classes,將類型系統(tǒng)上升到一個新的層次。

          泛型 attribute

          是的你沒有看錯,C# 的 attributes 支持泛型了:

          class TestAttribute<T> : Attribute
          {
              public T Data { get; }
              public TestAttribute(T data) { Data = data; }
          }

          然后你就能這么用了:

          [Test<int>(3)]
          [Test<float>(4.5f)]
          [Test<string>("hello")]

          允許在方法上指定 AsyncMethodBuilder

          C# 10 將允許方法上使用 [AsyncMethodBuilder(...)] 來使用你自己實現(xiàn)的 async method builder,代替自帶的 Task 或者 ValueTask 的異步方法構(gòu)造器。這也有助于你自己實現(xiàn)零開銷的異步方法。

          line 指示器支持行列和范圍

          以前 #line 只能用來指定一個文件中的某一行,現(xiàn)在可以指定行列和范圍了,這對寫編譯器和代碼生成器的人非常有用:

          #line (startLine, startChar) - (endLine, endChar) charOffset "fileName"
          // 比如 #line (1, 1) - (2, 2) 3 "test.cs"

          嵌套屬性模式匹配改進

          以前在匹配嵌套屬性的時候需要這么寫:

          if (a is { X: { Y: { Z: 4 } } }) { ... }

          現(xiàn)在只需要簡單的:

          if (a is { X.Y.Z: 4 }) { ... }

          就可以了。

          改進的字符串插值

          以前 C# 的字符串插值是很粗暴的 string.Format,并且對于值類型參數(shù)來說會直接裝箱,對于多個參數(shù)而言還會因此而分配一個數(shù)組(比如 string.Format("{} {}", a, b) 其實是 string.Format("{} {}", new object [] { (object)a, (object)b })),這很影響性能。現(xiàn)在字符串插值被改進了:

          var x = 1;
          Console.WriteLine($"hello, {x}");

          會被編譯成:

          int x = 1;
          DefaultInterpolatedStringHandler defaultInterpolatedStringHandler = new DefaultInterpolatedStringHandler(71);
          defaultInterpolatedStringHandler.AppendLiteral("hello, ");
          defaultInterpolatedStringHandler.AppendFormatted(x);
          Console.WriteLine(defaultInterpolatedStringHandler.ToStringAndClear());

          上面這個 DefaultInterpolatedStringHandler 也可以借助 InterpolatedStringHandler 這個 attribute 替換成你自己實現(xiàn)的插值處理器,來決定要怎么進行插值。借助這些可以實現(xiàn)接近零開銷的字符串插值。

          Source Generator v2

          代碼生成器在 C# 10 將會迎來 v2 版本,這個版本包含很多改進,包括強類型的代碼構(gòu)建器,以及增量編譯的支持等等。

          轉(zhuǎn)自:hez2010

          鏈接:cnblogs.com/hez2010/p/whats-new-in-csharp-10.html

          瀏覽 57
          點贊
          評論
          收藏
          分享

          手機掃一掃分享

          分享
          舉報
          評論
          圖片
          表情
          推薦
          點贊
          評論
          收藏
          分享

          手機掃一掃分享

          分享
          舉報
          <kbd id="afajh"><form id="afajh"></form></kbd>
          <strong id="afajh"><dl id="afajh"></dl></strong>
            <del id="afajh"><form id="afajh"></form></del>
                1. <th id="afajh"><progress id="afajh"></progress></th>
                  <b id="afajh"><abbr id="afajh"></abbr></b>
                  <th id="afajh"><progress id="afajh"></progress></th>
                  成人三级片二区 | 亚洲少妇xxx | 中文字幕三级片 | 毛片网站大全免费在线观看 | 欧美性猛交XXXXX按摩欧美 |