为什么应该用record来定义DTO

Posted dotNET跨平台

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了为什么应该用record来定义DTO相关的知识,希望对你有一定的参考价值。

DTO

DTO是数据传输对象(Data Transfer Object)的简称,主要用作在进程之间传送数据。

DTO的特点是它不包含任何业务逻辑或行为。

下面是一个典型的DTO定义:

public class UserDto
{
    public int Id { get; set; }
    public string Name { get; set; }
}

DTO的不变性

在实际使用中,我们并没有在进程之间来回传输具体的对象,而是使用某种形式的序列化,因此,DTO的属性不需要更改。

另外,考虑到DTO的用途,如果DTO的属性在传输过程中发生变化,数据将不再准确。

所以,DTO应该以无法更改的方式创建——它们应该是不可变的。

class实现方式

为什么以前没强调过DTO的不变性呢?因为在C#中实现是一件比较麻烦的事。

虽然我们可以定义私有setter来实现不可变类型,例如:

public class UserDto
{
    public UserDto(int id, string name)
    {
        this.Id = id;
        this.Name = name;
    }
    public int Id { get; private set; }
    public string Name { get; private set; }
}

从下图我们可以看到,值必须通过构造函数传递给属性。

而且正如预期的那样,我们无法在创建对象后再为属性赋值:

然而,这种方法有个很明显的缺点,如果我们增加一个属性,就必须调整一次构造函数。

record实现方式

从C# 9开始,可以使用record关键字定义一个引用类型,用来提供用于封装数据的内置功能。

它在设计上就具备创建具有不可变属性的能力。例如:

public record UserDto(int Id, string Name);

是不是非常简洁!

注意我们定义的是属性,所以参数用的PascalCase。

而且从下图我们可以看到,它与class创建对象方式相同。

同样在创建对象后不能再为属性赋值:

另外有一个附带的好处,如果增加了属性,立刻可以知道哪些代码位置需要修改:

public record UserDto(int Id, string Name, string Address);

结论

在本文中,我们介绍了record类型,它使得在C#中使用不可变DTO变得非常简单。

如果你觉得这篇文章对你有所启发,请关注我的个人公众号”My IO“,记住我!

以上是关于为什么应该用record来定义DTO的主要内容,如果未能解决你的问题,请参考以下文章

.NET 6新特性试用 | record struct

服务层应该接受来自控制器的 DTO 或自定义请求对象吗?

用简单的 POJO 或 DTO 对象替换这个持久化实体?

(扫盲)DTO数据传输对象

我可以重用代码来为 EF Core 的子属性选择自定义 DTO 对象吗?

DTO中的继承和自定义逻辑[关闭]