程序地带

使用 C# 9 的records作为强类型ID - 初次使用



强类型ID

实体通常是整数,GUID或者string类型,因为数据库直接支持这些类型,但是,如果实体的ID的类型是一样的,比如都是整数的ID,这有可能会出现ID值传错的问题,看下边的示例。


public void AddProductToOrder(int orderId, int productId, int count)
{
...
}
...
// 这个地方,参数传错了
AddProductToOrder(productId, orderId, int count);

上面的代码可以很好地通过检查并编译,但是在运行的时候就出问题了,这是逻辑bug。


幸运的是,可以定义强类型id来解决这个问题,这个想法很简单,为每个实体的ID声明一个特定的类型,现在需要这样写:


// 使用强类型ID代替整数ID
public void AddProductToOrder(OrderId orderId, ProductId productId, int count)
{
...
}
...
// 这个地方,参数传错了
AddProductToOrder(productId, orderId, int count);

在上面的代码中,我们犯了与第一个示例相同的错误(交换productId和orderId),但是在这种情况下,类型不同,因此编译器会捕获该错误并报告错误,我们仍然需要对其进行修复,但是至少在生产中并没有爆炸。


编写一个强类型的id
public readonly struct ProductId : IEquatable<ProductId>
{
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重写类型,就是下边这样:


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/


最后

欢迎扫码关注我们的公众号 【全球技术精选】,专注国外优秀博客的翻译和开源项目分享,也可以添加QQ群 897216102



版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://www.cnblogs.com/myshowtime/p/14285550.html

随机推荐

Python 实现验证哥德巴赫猜想

验证哥德巴赫猜想之一:2000以内的正偶数(大于等于4)都能够分解为两个质数之和。每个偶数表达成形如:4=2+2的形式ÿ...

鸭鸭很可爱 阅读(919)

java 多态判断非空_Java面向对象 —— 多态

java 多态判断非空_Java面向对象 —— 多态

前两天已经相继介绍了Java面向对象的三大特性之中的封装、继承,所以今天就介绍Java面向对象的三大特性的最后一项,多态~首先讲一下什么是多态,以及多态需要注...

weixin_39690963 阅读(393)

java 多态判断非空_硬核干货Java 面试题全梳理

Java基础篇Java有哪些特点并发性的:你可以在其中执行许多语句,而不必一次执行它面向对象的:基于类和面向对象的编程语言。独立性的:支持一次编...

weixin_39630140 阅读(237)

java中的日期时间类

java中的日期时间类

一、java.lang.System类System类提供的publicstaticlongcurrentTimeMillis()用来返回当前时间与1970年1月1日0时0分0秒之间以毫秒为单位的时间差...

改完这个bug就退休 阅读(163)

CSI-RS【5G笔记 1】

CSI-RS,channel-stateinformationreferencesignal,信道状态信息参考信号CSI可以包括:信息全称作用CRICSI-R...

sparrowHuhuhu 阅读(767)

AChartEngine –适用于Android应用程序的图表库

顾名思义,AChartEngine是一个图表库,可以在Android应用程序中使用。它支持1.6及更高版本的所有AndroidSDK版本。1.6版仅提供基于平移和按钮的缩放...

cunfen6312 阅读(186)

类重复引用_Java概念类面试题总结分享(附答案)

求职是每个人都要经历的过程,程序员想要进入自己期望的公司需求提前做好充分的准备,找到一份实用的面试题能起到很大的帮助。下面和大家分享Java概念相关的面试题,...

日月星辰只是陪衬 阅读(566)

增加校验功能

新建项目【HomeWork1】主布局资源文件activity_main.xml<?xmlversion="1.0"encoding="utf-8"...

triet 阅读(580)