浅析 record 使用场景
淺析 record 使用場景
Intro
之前我們有介紹過 record 基本知識,可以參考?C# 9 新特性 — record 解讀,record 會實現基于值的類型比較,最近遇到的幾個問題覺得用 record 來解決會非常方便,分享一下
基于值的類型比較
最近有遇到一個場景,需要比較兩個 JSON 字符串是否相等,字符串比較簡單,就是一個固定值的 Dictionary,或者認為它就是一個簡單的 Model,但是 JSON 字符串的的屬性順序可能不同,比如說下面的這個示例:
{"Id":1, "Name":"Tom"}, {"Name":"Tom", "Id":1},這兩個字符串從字符串上來說順序不同,自然不相等,但是對應的屬性的值是相同的,怎么比較方便的進行比較呢,使用 record 可以比較方便進行比較,來看代碼:
record?Person(int?Id,?string?Name);[Fact] public?void?RecordTest() {var?str1?=?"{\"Id\":1,?\"Name\":\"Tom\"}";var?p1?=?JsonConvert.DeserializeObject<Person>(str1);var?str2?=?"{\"Name\":\"Tom\",\"Id\":1}";var?p2?=?JsonConvert.DeserializeObject<Person>(str2);Assert.True(p1?==?p2);Assert.Equal(p1,?p2); }基于值比較的去重
我們有一個 API 有收到反饋說,調用多次返回的結果不同,于是我就想寫一段代碼調用個一百次看是否會有重復,大致代碼如下:
public?record?Result {public?string?Data?{?get;?set;}public?int?Code?{?get;?set;?} }var?i?=?100; var?results?=?new?HashSet<Result>(); using?var?httpClient?=?new?HttpClient(); while(i--?>?0) {var?responseText?=?await?httpClient.GetStringAsync("");var?result?=?JsonConvert.DeserializeObject<Result>(responseText);results.Add(result); } Console.WriteLine(results.Count);因為 record 不僅會重寫 Equals 方法還會重寫 GetHashCode 方法,所以可以使用 HashSet 或者 Dictionary ?來實現去重
對象克隆
record 提供了 with 表達式來方便的克隆一個新的對象,所以在需要克隆的時候可以考慮使用 record,另外所有原型模式的地方都可以考慮使用 record 來實現
之前我實現了一個簡單的日志框架,有一個日志對象,定義如下:
public?class?LogHelperLoggingEvent?:?ICloneable {public?string?CategoryName?{?get;?set;?}public?DateTimeOffset?DateTime?{?get;?set;?}public?string?MessageTemplate?{?get;?set;?}public?string?Message?{?get;?set;?}public?LogHelperLogLevel?LogLevel?{?get;?set;?}public?Dictionary<string,?object>?Properties?{?get;?set;?}public?LogHelperLoggingEvent?Copy()?{var?newEvent?=?new?LogHelperLoggingEvent(){CategoryName?=?CategoryName,DateTime?=?DateTime,MessageTemplate?=?MessageTemplate,Message?=?Message,LogLevel?=?LogLevel};if?(Properties?!=?null){newEvent.Properties?=?new?Dictionary<string,?object>();foreach?(var?property?in?Properties){newEvent.Properties[property.Key]?=?property.Value;}}return?newEvent;} }我們可以使用 MemberwiseClone 做一個簡化
public?class?LogHelperLoggingEvent?:?ICloneable {public?string?CategoryName?{?get;?set;?}public?DateTimeOffset?DateTime?{?get;?set;?}public?string?MessageTemplate?{?get;?set;?}public?string?Message?{?get;?set;?}public?LogHelperLogLevel?LogLevel?{?get;?set;?}public?Dictionary<string,?object>?Properties?{?get;?set;?}public?LogHelperLoggingEvent?Copy(){var?newEvent?=?(LogHelperLoggingEvent)MemberwiseClone();if?(Properties?!=?null){newEvent.Properties?=?new?Dictionary<string,?object>();foreach?(var?property?in?Properties){newEvent.Properties[property.Key]?=?property.Value;}}return?newEvent;} }使用了 record 之后如下,with 表達式返回的是強類型的對象,不再需要自己做強制類型轉換了,上面的做法還是比較取巧的辦法,使用了 MemberwiseClone 去做復制,如果自己寫代碼一個一個復制,將會更加繁瑣,使用 record 之后就很簡單了,只是我們需要注意一下,with 表達式也只是淺復制,如果內部包含復雜引用類型,需要小心使用
public?record?LogHelperLoggingEvent {public?string?CategoryName?{?get;?set;?}public?DateTimeOffset?DateTime?{?get;?set;?}public?string?MessageTemplate?{?get;?set;?}public?string?Message?{?get;?set;?}public?LogHelperLogLevel?LogLevel?{?get;?set;?}public?Dictionary<string,?object>?Properties?{?get;?set;?}public?LogHelperLoggingEvent?Copy(){var?newEvent?=?this?with{?};if?(Properties?!=?null){newEvent.Properties?=?new?Dictionary<string,?object>();foreach?(var?property?in?Properties){newEvent.Properties[property.Key]?=?property.Value;}}return?newEvent;} }More
record 在很多場景下能夠簡化我們的代碼,使得代碼更加干凈簡潔,在合適的場景下不要忘記使用哦~
微軟的反向代理項目 YARP 也使用了 record 來簡化原來代碼中 DeepClone 的功能,可以參考 PR:https://github.com/microsoft/reverse-proxy/pull/662
總結
以上是生活随笔為你收集整理的浅析 record 使用场景的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: C# ObservableCollect
- 下一篇: 后宫佳丽三千,假如古代皇帝也懂负载均衡算