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

DDD领域驱动设计:传入null时是否要创建字段全空的ValueObject值对象

问题1解答

建议你直接将null转换为new Address(null, null),核心原因是完全规避空引用风险:如果允许Address属性为null,后续所有调用该属性的代码都需要先做非空判断,一旦漏写就会抛出NullReferenceException,维护成本极高。
结合你的业务场景,City和Street本身就是非必填项,全空的Address对象刚好可以表达「未填写地址」的业务语义,比null的表意更清晰。
你可以额外做两个小优化:

  • 在Address类中定义静态只读的空实例复用,避免重复创建对象:public static readonly Address Empty = new Address(null, null);
  • 新增IsEmpty属性快速判断地址是否为空:public bool IsEmpty => string.IsNullOrWhiteSpace(City) && string.IsNullOrWhiteSpace(Street);

问题2解答

值对象没有「任何场景都必须创建」的硬性要求,完全按需设计即可,通用最佳实践可以参考这几点:

  • 保证不可变性:所有属性仅在构造函数中赋值,无公共setter,要修改值对象必须生成全新的实例,避免一处修改多处受影响的问题。C# 9及以上版本可以直接用record类型定义值对象,默认自带不可变性和值相等逻辑,减少模板代码。
  • 相等性基于属性值:两个值对象只要所有属性值完全一致就判定为相等,需要重写Equals和GetHashCode方法,避免引用相等带来的逻辑错误。
  • 用空对象替代null:除非业务上明确需要区分「没有值对象」和「值对象属性全空」两种状态,否则都建议用空值对象实例代替null,减少大量冗余的非空判断代码。
  • 相关逻辑内聚:值对象不要只做数据容器,和这组属性相关的业务逻辑(比如地址格式化输出、校验逻辑、同城市判断等)都要放到值对象内部实现,不要散落在外部服务中。
  • 仅对有业务意义的属性组抽值对象:如果多个属性是高频同时使用、有共同的业务语义,才需要抽成值对象,比如地址、金额(数值+币种)、坐标(经度+纬度)这类场景都很适合。如果只是零散的独立属性,硬凑成值对象反而会增加不必要的复杂度。

内容的提问来源于stack exchange,提问作者Max

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.09.30 01:18:03