C#中将数组元素赋值给变量后变量值随数组变动问题如何解决
问题本质
你用到的Clone()、CopyTo都属于数组的浅拷贝操作。由于PremiumBill是引用类型,数组中存储的只是对象在堆内存中的引用地址,浅拷贝仅会复制这些引用地址,不会创建新的PremiumBill对象实例。因此无论你从原数组还是克隆后的数组中取值,得到的x都指向同一个对象,只要原对象的属性被修改,x的取值自然会同步变化。
解决方案
无需克隆整个数组,只需要在取到目标对象后,单独对PremiumBill对象做深拷贝即可,常见实现方式如下:
- 手动实现深拷贝方法
在PremiumBill类中新增自定义拷贝方法,逐一复制所有属性值,如果存在嵌套的引用类型属性,需要对嵌套属性也做深拷贝处理:
取值时直接调用该方法即可:public class PremiumBill { public DateTime PostingDate { get; set; } // 其余自定义属性... public PremiumBill DeepClone() { return new PremiumBill { PostingDate = this.PostingDate, // 依次赋值所有需要保留的属性 // 若存在引用类型属性,需调用对应类的深拷贝方法 }; } }PremiumBill x = list.OrderBy(j => j.PostingDate) .FirstOrDefault(j => j.PostingDate >= input.PostingDate) ?.DeepClone(); - 序列化反序列化实现通用深拷贝
如果PremiumBill属性较多、嵌套结构复杂,可以用序列化反序列化的方式快速实现深拷贝,不需要手动编写每个属性的复制逻辑,示例用.NET内置的System.Text.Json实现:
注意:该方案要求var source = list.OrderBy(j => j.PostingDate).FirstOrDefault(j => j.PostingDate >= input.PostingDate); PremiumBill x = source == null ? null : JsonSerializer.Deserialize<PremiumBill>(JsonSerializer.Serialize(source));PremiumBill包含无参构造函数,且所有需要复制的属性支持序列化。 - 用record类型快速创建副本(.NET 5+支持)
若你的项目运行环境为.NET 5及以上版本,可以将PremiumBill定义为record类型,直接通过with表达式快速生成对象副本:// 类型定义 public record PremiumBill(DateTime PostingDate /* 其余属性参数 */); // 取值逻辑 var source = list.OrderBy(j => j.PostingDate).FirstOrDefault(j => j.PostingDate >= input.PostingDate); PremiumBill x = source with { };
内容的提问来源于stack exchange,提问作者Hadi Haidar
相关产品推荐
相关产品推荐

