Settings序列化器向带默认值的数组追加元素而非替换数组
问题:Settings.Default加载时列表元素被追加而非替换
加载Settings.Default时,自定义类型中的列表会出现反序列化元素追加到原有列表的问题,而非直接替换整个列表。
重现代码与配置
C#自定义设置类
class UserSettings { public List<string> foos = new() { "foo", "bar" }; }
Settings.Settings 文件内容
<?xml version='1.0' encoding='utf-8'?> <SettingsFile xmlns="http://schemas.microsoft.com/VisualStudio/2004/01/settings" CurrentProfile="(Default)" GeneratedClassNamespace="PhotoComparer.Properties" GeneratedClassName="Settings"> <Profiles /> <Settings> <Setting Name="UserSettings" Type="ProjectName.UserSettings" Scope="User"> <Value Profile="(Default)" /> </Setting> </Settings> </SettingsFile>
App.Config 文件内容
<?xml version="1.0" encoding="utf-8" ?> <configuration> <configSections> </configSections> </configuration>
问题重现步骤
- 新建
UserSettings实例,执行Settings.Default.Save()保存设置 - 关闭应用后重新启动,加载默认设置
- 此时
Settings.Default.UserSettings.foos变为包含4个元素的列表:{"foo", "bar", "foo", "bar"}
问题原因
.NET的Settings系统在反序列化自定义类型时,会复用类中已初始化的实例(这里是字段初始化时创建的List<string>对象),而非创建新实例并替换原有属性/字段。反序列化过程会将数据追加到已存在的列表中,导致元素重复。
解决方案
方案1:延迟初始化列表,避免字段初始化时创建实例
通过构造函数或属性懒加载的方式初始化列表,确保反序列化时可以直接替换整个列表实例:
// 构造函数初始化 class UserSettings { public List<string> foos; public UserSettings() { foos = new List<string> { "foo", "bar" }; } }
或使用属性懒加载:
class UserSettings { private List<string> _foos; public List<string> foos { get => _foos ??= new List<string> { "foo", "bar" }; set => _foos = value; } }
方案2:实现ISerializable接口手动控制反序列化
通过实现ISerializable接口,在反序列化时直接创建新的列表实例替换原有对象:
using System.Runtime.Serialization; class UserSettings : ISerializable { public List<string> foos = new() { "foo", "bar" }; // 无参构造函数必须保留 public UserSettings() { } protected UserSettings(SerializationInfo info, StreamingContext context) { // 反序列化时直接获取新列表,若为null则使用默认值 foos = (List<string>)info.GetValue("foos", typeof(List<string>)) ?? new List<string> { "foo", "bar" }; } public void GetObjectData(SerializationInfo info, StreamingContext context) { info.AddValue("foos", foos); } }
内容的提问来源于stack exchange,提问作者Doshorte Dovencio
相关产品推荐
相关产品推荐

