You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

C# record类型非破坏性突变时的属性条件赋值问题

关于C# Record在DTO条件更新中的疑问

场景与现状

我尝试将不可变的record类型用于部分DTO对象,发现非破坏性突变在简单属性赋值时写法简洁,但存在大量条件逻辑时会显得繁琐。

示例定义的Record:

public record MyDto
{
    int? Id { get; init; }
    // 其他无关属性
}

业务逻辑:调用GET接口获取MyDto数据,本地修改后通过PUT请求回传。核心需求是仅当满足条件时为属性赋值,否则保持原值,比如仅在overrideId不为null时更新Id属性。

当前实现:

public MyDto UpdateTheDto(MyDto dto, int? overrideId)
{
    return dto with
    {
        Id = overrideId ?? dto.Id
    };
}

疑问

  1. 是否有更优语法?例如,将Id改为可变(用set替代init)是否更好?
  2. 这会影响非破坏性突变的性能吗?官方文档提到非破坏性突变只会修改部分属性而非克隆整个record,但当overrideId为null、最终使用dto.Id时,编译器能否识别这是无操作,表现得如同未赋值Id一样?

同时不确定不可变record是否适合当前使用场景。


问题解答

1. 语法优化与可变属性的取舍

更简洁的条件赋值写法

你现在用??的写法已经够简洁了,如果要处理多属性的条件更新,写个针对性的扩展方法会更清爽:

// 给MyDto写专属扩展
public static MyDto WithIdIf(this MyDto dto, int? overrideId)
{
    return overrideId is null ? dto : dto with { Id = overrideId };
}

调用的时候直接return dto.WithIdIf(overrideId);,多属性的话还能链式调用,可读性拉满。要是有很多类似的属性要处理,这种方式比堆一堆??要干净得多。

改用set的利弊

改成set确实能让代码更直接:

public MyDto UpdateTheDto(MyDto dto, int? overrideId)
{
    if (overrideId != null)
        dto.Id = overrideId;
    return dto;
}

但代价是丢了不可变record的核心好处:不可变类型天生线程安全,而且不会出现“改了一个地方,其他引用这个DTO的地方也跟着变”的意外副作用。如果你的DTO会在多个方法、模块之间共享引用,这种隐性bug排查起来会很头疼。

2. 非破坏性突变的性能问题

先给你明确结论:编译器不会识别这种无意义的赋值。只要用了with表达式,不管你赋值的是不是原属性值,都会创建一个新的record实例,把原实例的所有属性值复制过来,再替换你指定的属性。

不过也不用慌,这种性能开销在DTO场景下基本可以忽略——record的复制是浅拷贝,值类型直接复制,引用类型只复制引用,速度非常快。真要在意的话,手动加个条件判断就行:

public MyDto UpdateTheDto(MyDto dto, int? overrideId)
{
    return overrideId == null ? dto : dto with { Id = overrideId };
}

这样当overrideId是null时直接返回原实例,不会创建新对象。

不可变Record是否适合当前场景?

看你的业务需求来定:

  • 如果你的DTO需要在多线程环境下用,或者要跨层传递、被多个地方引用,那不可变record绝对值得用——它能保证数据不会被偷偷修改,排查问题时能少掉好多头发。
  • 如果你的DTO只是在单个方法里临时修改,不会被多个地方共享引用,那用带set的record甚至普通class会更省事,省掉创建新实例的步骤。

大部分DTO场景下,我更推荐用不可变record,毕竟不可变性带来的稳定性,比那点微小的性能开销重要得多。


内容的提问来源于stack exchange,提问作者void.pointer

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.16 22:20:30