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

C#中Config对象数组引用异常:多实例意外共享数组值

C#中数组引用导致的配置实例数据异常问题

我们需要为板载的多个微控制器定义配置类Config,该类包含ConfigNum字段和长度为4的byte类型数组ConfigData。

第一种赋值方式:先创建Config实例再逐个赋值,运行完全正常。

第二种赋值方式:创建实例时用临时数组直接赋值给ConfigData,后续修改临时数组后,两个Config实例的ConfigData值意外同步变化,且无任何报错或警告,代码如下:

public class Config
{
    public byte ConfigNum { get; set; }
    public byte[] ConfigData { get; set; } = new byte[4];
}
static void Main()
{
    Config c0 = new Config();
    Config c1 = new Config();

    c0.ConfigNum = 11;
    c0.ConfigData[3] = 13;

    c1.ConfigNum = 22;
    c1.ConfigData[3] = 23;

    // 检查当前值
    Console.WriteLine(c0.ConfigNum); // 预期11
    Console.WriteLine(c0.ConfigData[3]); // 预期13
    Console.WriteLine(c1.ConfigNum); // 预期22
    Console.WriteLine(c1.ConfigData[3]); // 预期23

    // 尝试动态创建配置
    byte[] RConfigData1 = { 11, 12, 13, 14 }; // 创建临时数组

    Config c3 = new Config() // 用临时数组的值创建配置
    {
        ConfigNum = 55,
        ConfigData = RConfigData1
    };

    RConfigData1[3] = 24; // 修改临时数组的值

    Config c4 = new Config() // 再次用临时数组的值创建配置
    {
        ConfigNum = 66,
        ConfigData = RConfigData1
    };

    // 检查当前值
    Console.WriteLine(c3.ConfigNum); // 预期55
    Console.WriteLine(c3.ConfigData[3]); // 预期14但实际得到24
    Console.WriteLine(c4.ConfigNum); // 预期66
    Console.WriteLine(c4.ConfigData[3]); // 预期24
}

问题原因

数组是引用类型,当你将临时数组RConfigData1赋值给c3.ConfigData和c4.ConfigData时,并没有复制数组的内容,而是让这两个属性指向了同一个数组对象在内存中的地址。因此,修改临时数组的任何元素,都会同步影响所有指向该数组的引用对象。

解决方案

方案1:赋值时创建数组副本

在给ConfigData赋值时,通过Clone()方法创建数组的副本,避免共享同一引用:

Config c3 = new Config()
{
    ConfigNum = 55,
    ConfigData = (byte[])RConfigData1.Clone()
};

RConfigData1[3] = 24;

Config c4 = new Config()
{
    ConfigNum = 66,
    ConfigData = (byte[])RConfigData1.Clone()
};

方案2:修改Config类,自动处理数组副本

修改Config类的ConfigData属性,在setter中自动创建输入数组的副本,从根源避免外部引用污染:

public class Config
{
    public byte ConfigNum { get; set; }
    
    private byte[] _configData = new byte[4];
    public byte[] ConfigData
    {
        get => _configData;
        set => _configData = (byte[])value.Clone();
    }
}

这样无论外部传入哪个数组,Config实例都会保存自己的副本,后续修改原数组不会影响实例内的数据。

方案3:直接初始化新数组

每次创建Config实例时,直接初始化新的数组并赋值,不复用临时数组:

Config c3 = new Config()
{
    ConfigNum = 55,
    ConfigData = new byte[] { 11, 12, 13, 14 }
};

Config c4 = new Config()
{
    ConfigNum = 66,
    ConfigData = new byte[] { 11, 12, 13, 24 }
};

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.15 15:12:42