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
相关产品推荐
相关产品推荐

