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

C# Core 3.x中实现对象值复制(非引用)的方法,类比VB6的ByRef/ByVal

解决C# Core中对象赋值的引用关联问题

嗨,这个困扰我太懂了!咱们先搞清楚为什么会出现你说的情况,再一步步解决它。

首先,你遇到的核心问题是C#中引用类型的默认赋值行为:你定义的val类属于引用类型,当你执行val y = x;时,并不是把x的整个对象复制给y,而是把x指向堆上对象的引用地址复制给了y。这就相当于x和y拿着同一把钥匙开同一个柜子,不管谁改柜子里的东西(比如len属性),另一个人打开柜子看到的都是修改后的结果——所以你改y.len的时候,x.len也跟着变了。

对比VB6的ByRef/ByVal

VB6里的ByVal对于对象来说,其实是传递引用的副本,但C#里的逻辑有点不一样:

  • C#的方法参数默认是“传值”:对于值类型(比如int、struct),传的是值的副本;对于引用类型,传的是引用地址的副本。所以如果在方法里修改引用类型参数的属性,原对象会变,但如果把参数指向新对象,原对象不受影响。
  • 而ref关键字才类似VB6的ByRef,会直接传递原引用,修改参数指向的新对象时,原变量也会跟着变。

但你现在的场景是对象赋值,不是方法参数传递,所以得用其他方式断开引用。

具体解决方案

要让x和y指向不同的对象,你需要手动创建x的副本,常见的方式有这几种:

1. 实现复制构造函数

这是最直接的方式,在你的val类里写一个接收同类型对象的构造函数,把原对象的属性一一复制过来:

public class Val
{
    public int len { get; set; }

    // 复制构造函数
    public Val(Val original)
    {
        this.len = original.len;
        // 如果还有其他属性,也一一复制
    }
}

然后赋值的时候就用这个构造函数创建新对象:

x.len = 10;
Val y = new Val(x); // 创建x的副本
y.len = x.len * 2; // 现在y和x是两个独立对象,x.len还是10,y.len是20

2. 实现ICloneable接口

给类添加ICloneable接口,实现Clone方法,返回对象的副本:

public class Val : ICloneable
{
    public int len { get; set; }

    public object Clone()
    {
        // 浅拷贝:如果类里只有值类型属性,这样就够了
        return new Val { len = this.len };
    }
}

使用的时候:

Val y = (Val)x.Clone();

3. 深拷贝(如果类包含其他引用类型成员)

如果你的val类里还有其他引用类型的属性(比如另一个自定义类),上面的浅拷贝就不够了——因为只复制了引用地址,子对象还是共享的。这时候可以用序列化的方式实现深拷贝:

using System.Text.Json;

// 序列化x再反序列化,得到完全独立的新对象
var json = JsonSerializer.Serialize(x);
Val y = JsonSerializer.Deserialize<Val>(json);

这种方式不管对象嵌套多少层,都会创建全新的副本,缺点是性能比手动复制差一点,适合复杂对象。

总结

C#里没有VB6那种一键断开对象引用的语法糖,核心思路就是创建原对象的独立副本,根据你的对象复杂度选择合适的拷贝方式就行。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.06 23:37:50