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

歡迎訪問(wèn) 生活随笔!

生活随笔

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

C#

C# 9.0 正式发布了(C# 9.0 on the record)

發(fā)布時(shí)間:2023/12/4 C# 37 豆豆
生活随笔 收集整理的這篇文章主要介紹了 C# 9.0 正式发布了(C# 9.0 on the record) 小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.

翻譯自 Mads Torgersen 2020年11月10日的博文《C# 9.0 on the record》?[1],Mads Torgersen 是微軟 C# 語(yǔ)言的首席設(shè)計(jì)師,也是微軟 .NET 團(tuán)隊(duì)的項(xiàng)目群經(jīng)理。

C# 9.0 正式發(fā)布

正式宣布:C# 9.0 發(fā)布了!早在5月,我就寫了一篇關(guān)于 C# 9.0 計(jì)劃的博文?[2],以下是該帖子的更新版本,以匹配我們最終實(shí)際交付的產(chǎn)品。

對(duì)于 C# 的每一個(gè)新版本,我們都在努力讓常見(jiàn)編碼場(chǎng)景的實(shí)現(xiàn)變得更加清晰和簡(jiǎn)單,C# 9.0 也不例外。這次特別關(guān)注的是支持?jǐn)?shù)據(jù)模型的簡(jiǎn)潔和不可變表示。

一、僅初始化屬性

對(duì)象初始化器非常棒。它們?yōu)轭愋偷目蛻舳颂峁┝艘环N非常靈活和易讀的格式來(lái)創(chuàng)建對(duì)象,并且特別適合于嵌套對(duì)象的創(chuàng)建,讓你可以一次性創(chuàng)建整個(gè)對(duì)象樹(shù)。這里有一個(gè)簡(jiǎn)單的例子:

var person = new Person { FirstName = "Mads", LastName = "Torgersen" };

對(duì)象初始化器還使類型作者不必編寫大量的構(gòu)造函數(shù) —— 他們所要做的就是編寫一些屬性!

public class Person {public string? FirstName { get; set; }public string? LastName { get; set; } }

目前最大的限制是屬性必須是可變的(即可寫的),對(duì)象初始化器才能工作:它們首先調(diào)用對(duì)象的構(gòu)造函數(shù)(本例中是默認(rèn)的無(wú)參數(shù)構(gòu)造函數(shù)),然后賦值給屬性?setter。

僅初始化(init-only)屬性解決了這個(gè)問(wèn)題!它引入了一個(gè)?init?訪問(wèn)器,它是?set?訪問(wèn)器的變體,只能在對(duì)象初始化時(shí)調(diào)用:

public class Person {public string? FirstName { get; init; }public string? LastName { get; init; } }

有了這個(gè)聲明,上面的客戶端代碼仍然是合法的,但是隨后對(duì)?FirstName?和?LastName?屬性的任何賦值都是錯(cuò)誤的:

var person = new Person { FirstName = "Mads", LastName = "Nielsen" }; // OK person.LastName = "Torgersen"; // ERROR!

因此,僅初始化屬性可在初始化完成后保護(hù)對(duì)象的狀態(tài)免遭突變。

初始化訪問(wèn)器和只讀字段

因?yàn)?init?訪問(wèn)器只能在初始化期間調(diào)用,所以允許它們更改封閉類的只讀(readonly)字段,就像在構(gòu)造函數(shù)中一樣。

public class Person {private readonly string firstName = "<unknown>";private readonly string lastName = "<unknown>";public string FirstName{get => firstName;init => firstName = (value ?? throw new ArgumentNullException(nameof(FirstName)));}public string LastName{get => lastName;init => lastName = (value ?? throw new ArgumentNullException(nameof(LastName)));} }

二、記錄

經(jīng)典的面向?qū)ο缶幊痰暮诵乃枷胧?#xff0c;對(duì)象具有強(qiáng)大的身份并封裝了隨時(shí)間演變的可變狀態(tài)。C# 在這方面一直都很出色,但是有時(shí)您想要的恰恰相反,而在此時(shí),C# 的默認(rèn)設(shè)置往往會(huì)妨礙工作,使事情變得非常麻煩。

如果您發(fā)現(xiàn)自己希望整個(gè)對(duì)象是不可變的,并且行為像一個(gè)值,那么您應(yīng)該考慮將其聲明為記錄(record):

public record Person {public string? FirstName { get; init; }public string? LastName { get; init; } }

記錄仍然是類,但是?record?關(guān)鍵字賦予了它一些另外的類似于值的行為。一般來(lái)說(shuō),記錄是根據(jù)其內(nèi)容而不是其標(biāo)識(shí)來(lái)定義的。在這點(diǎn)上,記錄更接近于結(jié)構(gòu)體,但是記錄仍然是引用類型。

雖然記錄是可變的,但它們主要是為更好地支持不可變數(shù)據(jù)模型而構(gòu)建的。

with?表達(dá)式

處理不可變數(shù)據(jù)時(shí),一種常見(jiàn)的模式是從現(xiàn)有值創(chuàng)建新值以表示新?tīng)顟B(tài)。例如,如果我們的?person?要更改其?LastName,我們會(huì)將其表示為一個(gè)新對(duì)象,該對(duì)象是舊對(duì)象的副本,只是有不同的?LastName。這種技巧通常被稱之為非破壞性突變(non-destructive mutation)。記錄(record)不是代表?person?在一段時(shí)間內(nèi)的?狀態(tài),而是代表?person?在給定時(shí)間點(diǎn)的?狀態(tài)。

為了幫助實(shí)現(xiàn)這種編程風(fēng)格,記錄(record)允許使用一種新的表達(dá)式 ——?with?表達(dá)式:

var person = new Person { FirstName = "Mads", LastName = "Nielsen" }; var otherPerson = person with { LastName = "Torgersen" };

with?表達(dá)式使用對(duì)象初始化器語(yǔ)法來(lái)聲明新對(duì)象與舊對(duì)象的不同之處。您可以指定多個(gè)屬性。

with?表達(dá)式的工作原理是將舊對(duì)象的完整狀態(tài)實(shí)際地復(fù)制到一個(gè)新對(duì)象中,然后根據(jù)對(duì)象初始化器對(duì)其進(jìn)行改變。這意味著屬性必須具有?init?或?set?訪問(wèn)器才能在?with?表達(dá)式中進(jìn)行更改。

基于值的相等

所有對(duì)象都從對(duì)象類(object)繼承一個(gè)虛的?Equals(object)?方法。這被用作是當(dāng)兩個(gè)參數(shù)都是非空(non-null)時(shí),靜態(tài)方法?Object.Equals(object, object)?的基礎(chǔ)。

結(jié)構(gòu)體重寫了?Equals(object)?方法,通過(guò)遞歸地在結(jié)構(gòu)體的每一個(gè)字段上調(diào)用?Equals?來(lái)比較結(jié)構(gòu)體的每一個(gè)字段,從而實(shí)現(xiàn)了“基于值的相等”。記錄(record)是一樣的。

這意味著,根據(jù)它們的“值性(value-ness)”,兩個(gè)記錄(record)對(duì)象可以彼此相等,而不是同一個(gè)對(duì)象。例如,如果我們將被修改?person?的?LastName?改回去:

var originalPerson = otherPerson with { LastName = "Nielsen" };

現(xiàn)在我們將得到?ReferenceEquals(person, originalPerson)?=?false(它們不是同一個(gè)對(duì)象),但是?Equals(person, originalPerson)?=?true(它們有相同的值)。除了基于值的?Equals?之外,還有一個(gè)基于值的?GetHashCode()?重寫。另外,記錄實(shí)現(xiàn)了?IEquatable<T>?并且重載?==?和?!=?操作符,因此基于值的行為在所有這些不同的相等機(jī)制中表現(xiàn)一致。

值的相等性和可變性并不總是很好地融合在一起。一個(gè)問(wèn)題是,更改值可能導(dǎo)致?GetHashCode?的結(jié)果隨時(shí)間變化,如果對(duì)象存儲(chǔ)在哈希表中,這是很不幸的!我們不會(huì)禁止使用可變記錄,但是我們不鼓勵(lì)它們,除非您充分考慮過(guò)后果!

繼承

記錄可以從其他記錄繼承:

public record Student : Person {public int ID; }

with?表達(dá)式和值的相等性與記錄的繼承很好地結(jié)合在一起,因?yàn)樗鼈兛紤]了整個(gè)運(yùn)行時(shí)對(duì)象,而不僅僅是它的靜態(tài)已知類型。假設(shè)我創(chuàng)建了一個(gè)?Student,但將其存儲(chǔ)在?Person?變量中:

Person student = new Student { FirstName = "Mads", LastName = "Nielsen", ID = 129 };

with?表達(dá)式仍將復(fù)制整個(gè)對(duì)象并保留運(yùn)行時(shí)類型:

var otherStudent = student with { LastName = "Torgersen" }; WriteLine(otherStudent is Student); // true

以相同的方式,值的相等性確保兩個(gè)對(duì)象具有相同的運(yùn)行時(shí)類型,然后比較它們的所有狀態(tài):

Person similarStudent = new Student { FirstName = "Mads", LastName = "Nielsen", ID = 130 }; WriteLine(student != similarStudent); //true, 因?yàn)?ID 不同

位置記錄

有時(shí),對(duì)記錄采用更具位置定位的方法很有用,因?yàn)橛涗浀膬?nèi)容是通過(guò)構(gòu)造函數(shù)參數(shù)指定的,并且可以通過(guò)位置解構(gòu)來(lái)提取。完全可以在記錄(record)中指定您自己的構(gòu)造函數(shù)和解構(gòu)函數(shù):

public record Person {public string FirstName { get; init; }public string LastName { get; init; }public Person(string firstName, string lastName)=> (FirstName, LastName) = (firstName, lastName);public void Deconstruct(out string firstName, out string lastName)=> (firstName, lastName) = (FirstName, LastName); }

但是有一種更簡(jiǎn)短的語(yǔ)法來(lái)表達(dá)完全相同的意思(參數(shù)名稱包裝模式modulo casing of parameter names):

public record Person(string FirstName, string LastName);

它聲明了公共的僅初始化(init-only)自動(dòng)屬性以及構(gòu)造函數(shù)和解構(gòu)函數(shù),因此您就可以編寫:

var person = new Person("Mads", "Torgersen"); //用位置參數(shù)構(gòu)造(positional construction) var (f, l) = person; //用位置參數(shù)解構(gòu)(positional deconstruction)

如果不喜歡生成的自動(dòng)屬性,您可以定義自己的同名屬性,生成的構(gòu)造函數(shù)和解構(gòu)函數(shù)將只使用您自定義的屬性。在這種情況下,該參數(shù)在您用于初始化的作用域內(nèi)。舉例來(lái)說(shuō),假設(shè)您希望將?FirstName?設(shè)為受保護(hù)的屬性:

public record Person(string FirstName, string LastName) {protected string FirstName { get; init; } = FirstName; }

位置記錄可以像這樣調(diào)用基構(gòu)造函數(shù):

public record Student(string FirstName, string LastName, int ID) : Person(FirstName, LastName);

三、頂級(jí)程序

譯者注:
什么是 Top-level program ? 這是在頂級(jí)編寫程序的一種更簡(jiǎn)單的方式:一個(gè)更簡(jiǎn)單的?Program.cs?文件。

用 C# 編寫一個(gè)簡(jiǎn)單的程序需要大量的樣板代碼:

using System; class Program {static void Main(){Console.WriteLine("Hello World!");} }

這不僅對(duì)語(yǔ)言初學(xué)者來(lái)說(shuō)是難以承受的,而且還會(huì)使代碼混亂,增加縮進(jìn)級(jí)別。

在 C# 9.0 中,您可以在頂級(jí)編寫主程序(main program):

using System;Console.WriteLine("Hello World!");

允許任何語(yǔ)句。此程序必須在文件中的?using?語(yǔ)句之后,任何類型或命名空間聲明之前執(zhí)行,并且只能在一個(gè)文件中執(zhí)行。就像目前只能有一個(gè)?Main?方法一樣。
如果您想返回一個(gè)狀態(tài)碼,您可以做。如果您想等待(await)事情,您可以做。如果您想訪問(wèn)命令行參數(shù),args?可以作為一個(gè)“魔法”參數(shù)使用。

using static System.Console; using System.Threading.Tasks;WriteLine(args[0]); await Task.Delay(1000); return 0;

局部函數(shù)是語(yǔ)句的一種形式,也允許在頂級(jí)程序中使用。從頂級(jí)語(yǔ)句部分之外的任何地方調(diào)用它們都是錯(cuò)誤的。

四、改進(jìn)的模式匹配

C# 9.0 中添加了幾種新的模式。讓我們從模式匹配教程?[3]的以下代碼片段的上下文中來(lái)看看它們:

public static decimal CalculateToll(object vehicle) =>vehicle switch{...DeliveryTruck t when t.GrossWeightClass > 5000 => 10.00m + 5.00m,DeliveryTruck t when t.GrossWeightClass < 3000 => 10.00m - 2.00m,DeliveryTruck _ => 10.00m,_ => throw new ArgumentException("Not a known vehicle type", nameof(vehicle))};

簡(jiǎn)單類型模式

目前,類型模式需要在類型匹配時(shí)聲明一個(gè)標(biāo)識(shí)符 —— 即使該標(biāo)識(shí)符是一個(gè)棄元?_,如上面的?DeliveryTruck _?所示。但現(xiàn)在你只需寫下類型就可以了:

DeliveryTruck => 10.00m,

關(guān)系模式

C# 9.0 引入了與關(guān)系運(yùn)算符?<、<=?等相對(duì)應(yīng)的模式。因此,現(xiàn)在可以將上述模式的?DeliveryTruck?部分編寫為嵌套的?switch?表達(dá)式:

DeliveryTruck t when t.GrossWeightClass switch {> 5000 => 10.00m + 5.00m,< 3000 => 10.00m - 2.00m,_ => 10.00m, },

這里的?> 5000?和?< 3000?是關(guān)系模式。

邏輯模式

最后,您可以將模式與邏輯運(yùn)算符?and、or?和?not?組合起來(lái),這些運(yùn)算符用單詞拼寫,以避免與表達(dá)式中使用的運(yùn)算符混淆。例如,上面嵌套的?switch?的示例可以按如下升序排列:

DeliveryTruck t when t.GrossWeightClass switch {< 3000 => 10.00m - 2.00m,>= 3000 and <= 5000 => 10.00m,> 5000 => 10.00m + 5.00m, },

此例中間的案例使用?and?合并了兩個(gè)關(guān)系模式,形成一個(gè)表示區(qū)間的模式。

not?模式的一個(gè)常見(jiàn)用法是將其應(yīng)用于?null?常量模式,如?not null。例如,我們可以根據(jù)未知實(shí)例是否為空來(lái)拆分它們的處理:

not null => throw new ArgumentException($"Not a known vehicle type: {vehicle}", nameof(vehicle)), null => throw new ArgumentNullException(nameof(vehicle))

此外,not?在?if?條件中包含?is?表達(dá)式時(shí)將會(huì)很方便,可以取代笨拙的雙括號(hào),例如:

if (!(e is Customer)) { ... } // 舊的寫法

您可以寫成:

if (e is not Customer) { ... } // 新的寫法

實(shí)際上,在?is not?表達(dá)式中,允許您命名?Customer?以供后續(xù)使用:

if (e is not Customer c) { throw ... } // 如果此分支,則拋出異?;蚍祷?.. var n = c.FirstName; // ... 在這里,c 肯定已賦值

五、目標(biāo)類型的?new?表達(dá)式

“目標(biāo)類型(Target typing)”是我們?cè)诒磉_(dá)式從使用位置的上下文中獲取其類型時(shí)所用的一個(gè)術(shù)語(yǔ)。例如,null?和?lambda?表達(dá)式始終是目標(biāo)類型的。

C# 中的?new?表達(dá)式總是要求指定類型(隱式類型的數(shù)組表達(dá)式除外)。在 C# 9.0 中,如果表達(dá)式被賦值為一個(gè)明確的類型,則可以省略該類型。

Point p = new (3, 5);

當(dāng)您有很多重復(fù)時(shí),例如在數(shù)組或?qū)ο蟪跏蓟O(shè)定中,這特別地好用:

Point[] ps = { new (1, 2), new (5, 2), new (5, -3), new (1, -3) };

六、協(xié)變式返回值

有時(shí)候,這樣的表達(dá)是有用的 —— 派生類中的方法重寫,具有一個(gè)比基類型中的聲明更具體(更明確)的返回類型。C# 9.0 允許:

abstract class Animal {public abstract Food GetFood();... } class Tiger : Animal {public override Meat GetFood() => ...; }

更多內(nèi)容……

查看 C# 9.0 全部特性集的最好地方是?“What's new in C# 9.0” 文檔頁(yè)面?[4]。


相關(guān)鏈接:

  • https://devblogs.microsoft.com/dotnet/c-9-0-on-the-record/?C# 9.0 on the record???

  • https://mp.weixin.qq.com/s/0BWgiBuIxW-agyFNSejMtg?歡迎來(lái)到 C# 9.0???

  • https://docs.microsoft.com/en-us/dotnet/csharp/tutorials/pattern-matching?pattern matching tutorial???

  • https://docs.microsoft.com/dotnet/csharp/whats-new/csharp-9?What's new in C# 9.0???

  • 作者 :Mads Torgersen?

    譯者 :技術(shù)譯民?
    出品 :技術(shù)譯站(https://ITTranslator.cn/)

    總結(jié)

    以上是生活随笔為你收集整理的C# 9.0 正式发布了(C# 9.0 on the record)的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。

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