C# 人口及;使用自定义iDefaultContractResolver从Json合并对象集合会导致数据移位/损坏
这是我正在序列化/反序列化的类数据结构:C# 人口及;使用自定义iDefaultContractResolver从Json合并对象集合会导致数据移位/损坏,c#,json,json.net,C#,Json,Json.net,这是我正在序列化/反序列化的类数据结构: public class SettingGroup { public string name { get; set; } public string description { get; set; } public bool visible { get; set; } public ObservableCollection<SettingGroup> groups { get; set; } publi
public class SettingGroup
{
public string name { get; set; }
public string description { get; set; }
public bool visible { get; set; }
public ObservableCollection<SettingGroup> groups { get; set; }
public ObservableCollection<Setting> settings { get; set; }
public SettingGroup()
{
groups = new ObservableCollection<SettingGroup>();
settings = new ObservableCollection<Setting>();
visible = true;
}
}
public class Setting
{
public string name { get; set; }
public string description { get; set; }
public bool visible { get; set; }
public DescriptionVisibility descriptionVisibility { get; set; }
public Dictionary<string, dynamic> configuration { get; set; }
public dynamic settingValue { get; set; }
public SettingType settingType { get; set; }
public SettingControl settingControl { get; set; }
public Setting()
{
visible = true;
configuration = new Dictionary<string, dynamic>();
}
}
自定义iDefaultContractResolver是我在SE中看到的一个,但出于完整性考虑,这里将包括:
public class IgnorableSerializerContractResolver : DefaultContractResolver
{
protected readonly Dictionary<Type, HashSet<string>> Ignores;
public IgnorableSerializerContractResolver()
{
this.Ignores = new Dictionary<Type, HashSet<string>>();
}
public void Ignore(Type type, params string[] propertyName)
{
if (!this.Ignores.ContainsKey(type)) this.Ignores[type] = new HashSet<string>();
foreach (var prop in propertyName)
{
this.Ignores[type].Add(prop);
}
}
public bool IsIgnored(Type type, string propertyName)
{
if (!this.Ignores.ContainsKey(type)) return false;
// if no properties provided, ignore the type entirely
if (this.Ignores[type].Count == 0) return true;
return this.Ignores[type].Contains(propertyName);
}
protected override JsonProperty CreateProperty(MemberInfo member, MemberSerialization memberSerialization)
{
JsonProperty property = base.CreateProperty(member, memberSerialization);
if (this.IsIgnored(property.DeclaringType, property.PropertyName)
// need to check basetype as well for EF -- @per comment by user576838
|| this.IsIgnored(property.DeclaringType.BaseType, property.PropertyName))
{
property.ShouldSerialize = instance => { return false; };
}
return property;
}
}
编辑以包含Json源和结果:
具有设置信息和默认值的完整Json结构:
{
"name": "Application Settings",
"description": "Common application settings.",
"visible": true,
"groups": [
{
"name": "General settings",
"description": null,
"visible": true,
"groups": [
{
"name": "Startup settings",
"description": null,
"visible": true,
"groups": [],
"settings": [
{
"name": "Start IM with Windows",
"description": null,
"visible": true,
"descriptionVisibility": 0,
"configuration": {},
"settingValue": true,
"settingType": 0,
"settingControl": 0
},
{
"name": "Start IM minimized",
"description": null,
"visible": true,
"descriptionVisibility": 0,
"configuration": {},
"settingValue": true,
"settingType": 0,
"settingControl": 0
}
]
},
{
"name": "Performance settings",
"description": null,
"visible": true,
"groups": [],
"settings": [
{
"name": "Thread priority",
"description": "This setting may not have a noticeible impact on all platforms, especially higer end ones.",
"visible": true,
"descriptionVisibility": 0,
"configuration": {
"lowVal": 0,
"highVal": 7,
"interval": 1
},
"settingValue": 3,
"settingType": 0,
"settingControl": 2
}
]
}
],
"settings": []
},
{
"name": "Theme settings",
"description": null,
"visible": true,
"groups": [],
"settings": []
},
{
"name": "Update settings",
"description": null,
"visible": true,
"groups": [],
"settings": []
},
{
"name": "General settings",
"description": null,
"visible": true,
"groups": [
{
"name": "Startup settings",
"description": null,
"visible": true,
"groups": [],
"settings": [
{
"name": "Start IM with Windows",
"description": null,
"visible": true,
"descriptionVisibility": 0,
"configuration": {},
"settingValue": true,
"settingType": 0,
"settingControl": 0
},
{
"name": "Start IM minimized",
"description": null,
"visible": true,
"descriptionVisibility": 0,
"configuration": {},
"settingValue": true,
"settingType": 0,
"settingControl": 0
}
]
},
{
"name": "Performance settings",
"description": null,
"visible": true,
"groups": [],
"settings": [
{
"name": "Thread priority",
"description": null,
"visible": true,
"descriptionVisibility": 0,
"configuration": {},
"settingValue": 3,
"settingType": 0,
"settingControl": 0
}
]
}
],
"settings": []
},
{
"name": "Theme settings",
"description": null,
"visible": true,
"groups": [],
"settings": []
},
{
"name": "Update settings",
"description": null,
"visible": true,
"groups": [],
"settings": []
}
],
"settings": []
}
由my saveSettings扩展保存的数据,该扩展旨在仅保存所需的信息,如组名子项以及设置名称和值(看起来正确)
但当加载并与现有类对象合并时,结果数据就是这样的,请注意控件类型中的重复值和无效值会导致类型不匹配,即无法将long
值加载到复选框使用的bool
{
"name": "Application Settings",
"description": "Common application settings.",
"visible": true,
"groups": [
{
"name": "General settings",
"description": null,
"visible": true,
"groups": [
{
"name": "Startup settings",
"description": null,
"visible": true,
"groups": [],
"settings": [
{
"name": "Start IM with Windows",
"description": null,
"visible": true,
"descriptionVisibility": 0,
"configuration": {},
"settingValue": true,
"settingType": 0,
"settingControl": 0
},
{
"name": "Start IM minimized",
"description": null,
"visible": true,
"descriptionVisibility": 0,
"configuration": {},
"settingValue": true,
"settingType": 0,
"settingControl": 0
}
]
},
{
"name": "Performance settings",
"description": null,
"visible": true,
"groups": [],
"settings": [
{
"name": "Thread priority",
"description": "This setting may not have a noticeible impact on all platforms, especially higer end ones.",
"visible": true,
"descriptionVisibility": 0,
"configuration": {
"lowVal": 0,
"highVal": 7,
"interval": 1
},
"settingValue": 3,
"settingType": 0,
"settingControl": 2
}
]
}
],
"settings": []
},
{
"name": "Theme settings",
"description": null,
"visible": true,
"groups": [],
"settings": []
},
{
"name": "Update settings",
"description": null,
"visible": true,
"groups": [],
"settings": []
},
{
"name": "General settings",
"description": null,
"visible": true,
"groups": [
{
"name": "Startup settings",
"description": null,
"visible": true,
"groups": [],
"settings": [
{
"name": "Start IM with Windows",
"description": null,
"visible": true,
"descriptionVisibility": 0,
"configuration": {},
"settingValue": true,
"settingType": 0,
"settingControl": 0
},
{
"name": "Start IM minimized",
"description": null,
"visible": true,
"descriptionVisibility": 0,
"configuration": {},
"settingValue": true,
"settingType": 0,
"settingControl": 0
}
]
},
{
"name": "Performance settings",
"description": null,
"visible": true,
"groups": [],
"settings": [
{
"name": "Thread priority",
"description": null,
"visible": true,
"descriptionVisibility": 0,
"configuration": {},
"settingValue": 3,
"settingType": 0,
"settingControl": 0
}
]
}
],
"settings": []
},
{
"name": "Theme settings",
"description": null,
"visible": true,
"groups": [],
"settings": []
},
{
"name": "Update settings",
"description": null,
"visible": true,
"groups": [],
"settings": []
}
],
"settings": []
}
您应该能够从中使用
KeyedListMergeConverter
(而不是专门用于合并列表
集合的原始KeyedListMergeConverter
),将[JsonMergeKey]
附加到名称:
public class SettingGroup
{
[JsonMergeKey]
public string name { get; set; }
// Remainder unchanged
}
public class Setting
{
[JsonMergeKey]
public string name { get; set; }
// Remainder unchanged
}
然后像这样使用它:
if (!Directory.Exists(Global.DataDirectory))
Directory.CreateDirectory(Global.DataDirectory);
var serializerSettings = new JsonSerializerSettings { ObjectCreationHandling = ObjectCreationHandling.Auto, ContractResolver = jsonResolver };
serializerSettings.Converters.Add(new KeyedIListMergeConverter(settings.ContractResolver));
JsonConvert.PopulateObject(File.ReadAllText(Path.Combine(Global.DataDirectory, fileName + ".json")), settingGroup, serializerSettings);
我认为为我的数据指定一个键可以解决我的问题,这是正确的吗@dbc添加了一些Json转储,以说明最终Json数据中的数据通知发生了什么,它应该是前两个的叠加结果,数据实际上是重复的,
性能设置
第二次出现时,设置控件
属性本身设置为0。我无法重现您的问题。每次我使用您的IgnorableSerializerContractResolver
往返您的设置组
,结果都会原封不动地返回。看见您提到了一些关于“合并”的内容,因此,如果您能创建一个可复制的合并问题示例,我们可能会提供帮助。@dbc我不确定您想在这里演示什么,正如我所说的,设置文件保存并看起来与预期的一样,但当它合并回设置对象时,它会在其中创建重复项,因为据我所知,小提琴无法暂停执行,无法窥视设置对象以查看坏数据,所以这不会说明问题。在本例中,您可以看到合并的数据只是重复。啊,第一印象是,这工作非常出色!如果问题真的解决了,我会考虑一下,然后回来接受答案。
{
"name": "Application Settings",
"description": "Common application settings.",
"visible": true,
"groups": [
{
"name": "General settings",
"description": null,
"visible": true,
"groups": [
{
"name": "Startup settings",
"description": null,
"visible": true,
"groups": [],
"settings": [
{
"name": "Start IM with Windows",
"description": null,
"visible": true,
"descriptionVisibility": 0,
"configuration": {},
"settingValue": true,
"settingType": 0,
"settingControl": 0
},
{
"name": "Start IM minimized",
"description": null,
"visible": true,
"descriptionVisibility": 0,
"configuration": {},
"settingValue": true,
"settingType": 0,
"settingControl": 0
}
]
},
{
"name": "Performance settings",
"description": null,
"visible": true,
"groups": [],
"settings": [
{
"name": "Thread priority",
"description": "This setting may not have a noticeible impact on all platforms, especially higer end ones.",
"visible": true,
"descriptionVisibility": 0,
"configuration": {
"lowVal": 0,
"highVal": 7,
"interval": 1
},
"settingValue": 3,
"settingType": 0,
"settingControl": 2
}
]
}
],
"settings": []
},
{
"name": "Theme settings",
"description": null,
"visible": true,
"groups": [],
"settings": []
},
{
"name": "Update settings",
"description": null,
"visible": true,
"groups": [],
"settings": []
},
{
"name": "General settings",
"description": null,
"visible": true,
"groups": [
{
"name": "Startup settings",
"description": null,
"visible": true,
"groups": [],
"settings": [
{
"name": "Start IM with Windows",
"description": null,
"visible": true,
"descriptionVisibility": 0,
"configuration": {},
"settingValue": true,
"settingType": 0,
"settingControl": 0
},
{
"name": "Start IM minimized",
"description": null,
"visible": true,
"descriptionVisibility": 0,
"configuration": {},
"settingValue": true,
"settingType": 0,
"settingControl": 0
}
]
},
{
"name": "Performance settings",
"description": null,
"visible": true,
"groups": [],
"settings": [
{
"name": "Thread priority",
"description": null,
"visible": true,
"descriptionVisibility": 0,
"configuration": {},
"settingValue": 3,
"settingType": 0,
"settingControl": 0
}
]
}
],
"settings": []
},
{
"name": "Theme settings",
"description": null,
"visible": true,
"groups": [],
"settings": []
},
{
"name": "Update settings",
"description": null,
"visible": true,
"groups": [],
"settings": []
}
],
"settings": []
}
public class SettingGroup
{
[JsonMergeKey]
public string name { get; set; }
// Remainder unchanged
}
public class Setting
{
[JsonMergeKey]
public string name { get; set; }
// Remainder unchanged
}
if (!Directory.Exists(Global.DataDirectory))
Directory.CreateDirectory(Global.DataDirectory);
var serializerSettings = new JsonSerializerSettings { ObjectCreationHandling = ObjectCreationHandling.Auto, ContractResolver = jsonResolver };
serializerSettings.Converters.Add(new KeyedIListMergeConverter(settings.ContractResolver));
JsonConvert.PopulateObject(File.ReadAllText(Path.Combine(Global.DataDirectory, fileName + ".json")), settingGroup, serializerSettings);