1. 程式人生 > >使用 C# 9 的records作為強型別ID - 初次使用

使用 C# 9 的records作為強型別ID - 初次使用

![](https://blog-1259586045.cos.ap-shanghai.myqcloud.com/clipboard_20210116_124242.png) ### 強型別ID 實體通常是整數,GUID或者string型別,因為資料庫直接支援這些型別,但是,如果實體的ID的型別是一樣的,比如都是整數的ID,這有可能會出現ID值傳錯的問題,看下邊的示例。 ```csharp public void AddProductToOrder(int orderId, int productId, int count) { ... } ... // 這個地方,引數傳錯了 AddProductToOrder(productId, orderId, int count); ``` 上面的程式碼可以很好地通過檢查並編譯,但是在執行的時候就出問題了,這是邏輯bug。 幸運的是,可以定義強型別id來解決這個問題,這個想法很簡單,為每個實體的ID宣告一個特定的型別,現在需要這樣寫: ```csharp // 使用強型別ID代替整數ID public void AddProductToOrder(OrderId orderId, ProductId productId, int count) { ... } ... // 這個地方,引數傳錯了 AddProductToOrder(productId, orderId, int count); ``` 在上面的程式碼中,我們犯了與第一個示例相同的錯誤(交換productId和orderId),但是在這種情況下,型別不同,因此編譯器會捕獲該錯誤並報告錯誤,我們仍然需要對其進行修復,但是至少在生產中並沒有爆炸。 ### 編寫一個強型別的id ```csharp public readonly struct ProductId : IEquatable { public ProductId(int value) { Value = value; } public int Value { get; } public bool Equals(ProductId other) => other.Value == Value; public override bool Equals(object obj) => obj is ProductId other && Equals(other); public override int GetHashCode() => Value.GetHashCode(); public override string ToString() => $"ProductId {Value}"; public static bool operator ==(ProductId a, ProductId b) => a.Equals(b); public static bool operator !=(ProductId a, ProductId b) => !a.Equals(b); } ``` 上面的程式碼沒什麼難的,但是如果每個實體都需要的話,那確實有點麻煩,在C# 9 可以使用source generators來完成這些,但是C# 9還引入了另一個功能,使用起來更方便。 ### Record型別 Record 型別是具有內建不變性和值語義的引用型別,它和上面我們寫的強型別是一樣的(手動寫的成員實現Equals,GetHashCode等等),在程式碼中使用也非常簡潔, 如果我們ProductId使用record重寫型別,就是下邊這樣: ```csharp public record ProductId(int Value); ``` 是的,您沒看錯,這是一行,而上面的程式碼是一大段,它完成了我們手動執行的所有操作(實際上,還多了很多!)。 主要區別在於:我們的手動實現是struct,即值型別,但是記錄是引用型別,這意味著它們可以為null,這可能不是主要問題,尤其是在使用可為空的引用型別的情況下,但是要知道這一點。 現在為模型中的每個實體編寫一個強型別的id是不是很簡單,使用Record 非常方便,當然,還有其他問題需要考慮,例如JSON序列化,與Entity Framework Core一起使用等,但這是另一篇文章的故事! > 原文作者: thomas levesque > 原文連結:[https://thomaslevesque.com/2020/10/30/using-csharp-9-records-as-strongly-typed-ids/](https://thomaslevesque.com/2020/10/30/using-csharp-9-records-as-strongly-typed-ids/ "https://thomaslevesque.com/2020/10/30/using-csharp-9-records-as-strongly-typed-ids/") ### 最後 歡迎掃碼關注我們的公眾號 【全球技術精選】,專注國外優秀部落格的翻譯和開源專案分享,也可以新增QQ群 897216102

相關推薦

使用 C# 9records作為型別ID - 初次使用

![](https://blog-1259586045.cos.ap-shanghai.myqcloud.com/clipboard_20210116_124242.png) ### 強型別ID 實體通常是整數,GUID或者string型別,因為資料庫直接支援這些型別,但是,如果實體的ID的型別是一樣的,

使用 C# 9records作為型別ID - 路由和查詢引數

![](https://blog-1259586045.cos.ap-shanghai.myqcloud.com/clipboard_20210117_120835.png) 上一篇文章,我介紹了使用 C# 9 的record型別作為強型別id,非常簡潔 ```csharp public record P

使用 C# 9records作為型別ID - JSON序列化

![](https://blog-1259586045.cos.ap-shanghai.myqcloud.com/clipboard_20210118_060642.png) 在本系列的上一篇文章中,我們注意到強型別ID的實體,序列化為 JSON 的時候報錯了,就像這樣: ```csharp {

Cocos2dx 3.0 過渡篇(二十八)C++11型別列舉

一朋友在微信朋友圈晒了張照片,隨手點開大圖,帶著讚賞的眼光掃了下,恩,幾個月不見。又美麗了...咦?等等,她戴的這是什麼? 酷炫的造型!金屬邊框!微型攝像頭! 這不是傳說中的谷歌眼鏡麼?土豪啊,還好我們已經是朋友了...我先給了她一個贊,然後直奔主題,霸氣回覆道:我過幾天去找你,你

C++傳入任意的函式型別作為引數

C++程式設計中,有些時候需要傳入函式作為引數,這在STL中作為謂詞經常用到。傳入的可以是函式、函式物件和lambda表示式。程式設計的時候,把它當成一個模板型別傳入即可。以下給出一個簡單的例子: #include <iostream> #include <util

知識點總結: c#,使用自定義型別作為Dictionary的Key

首先來看一個變數的定義: /// <summary> /// key依次是StationId,channelId,deviceId,paraType,dataId,dataTypeId,logicalDeviceIndex,paraHandle,

C++11型別列舉

1.傳統列舉型別的缺陷 列舉型別是C/C++中使用者自定義的構造型別,它是由使用者定義的若干列舉常量的集合。列舉值對應整型數值,預設從0開始。比如定義一個描述性別的列舉型別。 enum Gender{Male,Female}; 其中列舉值Male被編譯器預設賦值為0,Fem

c# 中的泛型以及型別與弱型別

一直說C#是強型別語言,通俗地講,便是指C#中的“變數”在開發時其型別便是明確的:String便是String,Int32就是Int32。強型別的語言有以下幾點好處: 1.能夠享受程式碼提示功能 2.能夠獲得重構工具的支援  3.能夠在編譯期發現更多錯誤  與強型別相對的就

c++11實現型別快取系統

提示: 開篇:     看到這篇文章,或許你會有以下疑問:     現在有各種開源的記憶體k-v快取資料庫,為啥要自己搞一個?     幾點解釋:         1. 這些k-v系統一般都比較重量級,當然相對於關係型資料庫可能還好,但是相對於我的這個實現來說絕對是重

Modern C++(六)型別列舉enum

我們都知道在C++11前的列舉型別是預設為int型別,不是強型別的,所以毫無關係的兩個列舉型別可以進行比較 enum EnumA { A = 1, B = 2 }; enum EnumB { C = 1, D = 2 };

c++11】 enum class: 型別列舉

#include <iostream> int _tmain(int argc, _TCHAR* argv[]) {     // 1、列舉型別的定義:     // 普通列舉常量作用域提升至外圍(main函式之內)並且可以整型提升     enum Numb

C#型別資料集的多資料庫應用

        object loginhistoryAdapter;//弱型別的介面卡         public loginhistory()         {             if (dbtype1 == "SQLServer")             {                 

C++中傳統列舉和型別列舉的區別?

傳統列舉型別定義舉例: enum Animal  //列舉型別名字 {        monkey, //列舉中的元素值        horse,        lion,        eleph

C++11:型別列舉(enum)

// C++11之前的enum型別是繼承C的,不溫不火; // C++11對enum動刀了,加強了型別檢查,推出強型別enum型別,眼前一亮 // 使用過QT 的都知道,早就應該這麼做了,用的很爽!! // 一、C中enum型別的侷限 // 1、非強型別作用域 enum

一個茴字有三種寫法——吐槽C#9.0的Records

最近是微軟開了Build 2020大會,由於疫情原因,改成了線上舉行,Build大會上,C#公佈9.0版本。 我個人對於C#的更新向來都是喜聞樂見,樂於接受的,對於部落格園上某些人天天嘲諷C#只會增加語法糖的人,我向來對他們不屑一顧,認為他們是井底之蛙。 因此我仔細看了微軟發的文章[Welcome to

C# 9.0 新特性之目標型別推導 new 表示式

閱讀本文大概需要 2 分鐘。 呼~~,每次過完一個週末,寫作就失去了動力,一兩天才能緩過來。儘管如此,還是要堅持寫好每一篇文章的。寧缺毋濫嘛,寧願發文的頻率低一點,也要保證文章的質量,至少排版不能差,行文要流暢,錯別字不能有。 關於**型別推導**想必大家都很熟悉,它是在 var 關鍵字引入的時候引入 C

C#9.0:Records

概述 在C#9.0下,record是一個關鍵字,微軟官方目前暫時將它翻譯為記錄型別。 傳統面向物件的程式設計的核心思想是一個物件有著唯一標識,封裝著隨時可變的狀態。C#也是一直這樣設計和工作的。但是一些時候,你就非常需要剛好對立的方式。原來那種預設的方式往往會成為阻力,使得事情變得費時費力。如果你發現你需要整

c++將lambda作為callback函數

include lam 如果 pen init func per result out 想用c++發送http_post請求,用到了libcurl。 想將其包裝一下,因為默認http的響應結果是打印到stdout的,如果想將響應結果另外處理,需要自己定義一個callbac

Python error: Microsoft Visual C++ 9.0 is required 解決方案

compile blank 安裝ipython con pan code logs onf pre 換了新電腦,在使用python2.7 pip 安裝ipython時,報錯了 error: Microsoft Visual C++ 9.0 is required. Get

C#的幾種轉的整理

系統 一點 內容 float 轉型 是你 false pty 精度 fool me once, shame on you ; fool me twice,shame on me; 1、(int)變量名[強制類型轉換] 該轉換方式多用於數字類型的轉換從int轉到long、d