我正在尝试更新Json序列化类中已经发布的属性名称,因此我需要使其向后兼容。
public class myClass
{
//[JsonIgnore] - now old json files can't be read, so this won't work...
//[JsonProperty(ReferenceLoopHandling = ReferenceLoopHandling.Error)] - didn't do anything
//[JsonProperty(nameof(NewName)] - throws error - "That already exists"
[Obselete("Use NewName instead")]
public List<string> OldName { get => newName; set => newName = value; }
public List<string> NewName { get; set; } = new List<string>();
}
我这样使用它:
[Test]
public void test()
{
var foo = new myClass()
{
OldName = { "test" },
};
var bar = JsonConvert.SerializeObject(foo);
var result = JsonConvert.DeserializeObject(bar, typeof(myClass));
}
当我查看result中的值时。NewName,我发现这个列表:{"test", "test"}
,但我期望这个列表:{"test"}
期望的行为:
- 如果有人已经在他们的代码中使用OldName,他们得到一个过时的警告
- 如果有人解析带有OldName的旧json文件,它会正确映射到NewName
- 新创建的json文件使用NewName,而OldName在json文件中找不到
- 在任何情况下都不能将值反序列化两次并放入同一个列表
您将如何实现这一点?
试试这个
var foo = "{"OldName":["old test"]}";
var fooN = "{"NewName":["new test"]}";
var result = JsonConvert.DeserializeObject(foo, typeof(myClass));
//or
var result = JsonConvert.DeserializeObject(fooN, typeof(myClass));
var json = JsonConvert.SerializeObject(result);
json结果:
{"NewName":["new test"]}
//or
{"NewName":["old test"]}
类
public class myClass
{
[JsonProperty(NullValueHandling = NullValueHandling.Ignore)]
public List<string> OldName {
get {return null; }
set {NewName=value;}
}
public List<string> NewName {get; set;}
}
使用System.Text.Json。
var foo = new myClass()
{
OldName = { "test" },
};
var bar = JsonSerializer.Serialize<myClass>(foo);
var result = JsonSerializer.Deserialize<myClass>(bar);
这个回答很有帮助。基本上你可以这样重构你的代码:
public class ControlReportResult : TargetReportResult
{
public List<string> NewName { get; set; } = new();
[JsonIgnore] // this stops the serializer from paying attention to this property
[Obsolete("Use NewName instead")]
public List<string> OldName => { get => NewName; set => NewName = value; }
[JsonProperty("OldName")] //This doesn't throw an error because the serializer was told to ignore the real OldName property
private List<string> _jsonOldNameSetter { set => NewName = value; } // no getter, so we are never going to write OldName out.
}
一些注意事项:
- _jsonOldNameSetter是私有的,所以你的界面仍然干净
- OldName仍然可用,但标记为obselete 代码将在json文件中读取或者OldName或NewName,但只写入NewName的文件
这是不应该发生的,但如果你仍然以某种方式结束json文件与一个OldName和一个NewName,在OldName和NewName上面添加属性[JsonProperty(ObjectCreationHandling = ObjectCreationHandling.Replace)]
-这样它们会相互覆盖,而不是追加。