如果您愿意切换到 JSON.net,那么有一种更简单的方法。您不必使用包含version 的BaseClass,也不必解析两次。诀窍是使用JObject,然后使用query JSON 作为version:
JObject obj = JObject.Parse(json);
string version = obj.SelectToken("$.Version")?.ToString();
然后您可以像 Sándor 一样继续使用奖励部分,您可以使用 JObject 获取您的 dto 而不是重新读取 json:
ConditionsDto v1Dto = obj.ToObject<ConditionsDto>(readSerializer);
把它们放在一起:
public static ConditionsBusinessObject Parse(string json)
{
JObject obj = JObject.Parse(json);
string version = obj.SelectToken("$.Version")?.ToString();
JsonSerializer readSerializer = JsonSerializer.CreateDefault(/*You might want to place your settings here*/);
switch (version)
{
case null: //let's assume that there are some old files out there with no version at all
//and that these are equivalent to the version 1
case "1":
ConditionsDto v1Dto = obj.ToObject<ConditionsDto>(readSerializer);
if (v1Dto == null) return null; //or throw
List<string> convertedConditions = new List<string> {v1Dto.Condition}; //See what I've done here?
return new ConditionsBusinessObject(convertedConditions);
case "2":
ConditionsDtoV2 v2Dto = obj.ToObject<ConditionsDtoV2>(readSerializer);
return v2Dto == null ? null //or throw
: new ConditionsBusinessObject(v2Dto.Condition);
default:
throw new Exception($"Unsupported version {version}");
}
}
以下是我拥有的课程供参考:
public class ConditionsDto
{
public string Version { get; set; }
public string Condition { get; set; }
}
public class ConditionsDtoV2
{
public string Version { get; set; }
public List<string> Condition { get; set; }
}
public class ConditionsBusinessObject
{
public ConditionsBusinessObject(List<string> conditions)
{
Conditions = conditions;
}
public List<string> Conditions { get; }
}
还有几个测试来结束它:
[Test]
public void TestV1()
{
string v1 = @"{
Version: ""1"",
Condition: ""A < B""
}";
//JsonHandler is where I placed Parse()
ConditionsBusinessObject fromV1 = JsonHandler.Parse(v1);
Assert.AreEqual(1, fromV1.Conditions.Count);
Assert.AreEqual("A < B", fromV1.Conditions[0]);
}
[Test]
public void TestV2()
{
string v2 = @"{
Version: ""2"",
Condition: [""A < B"", ""B = C"", ""B < 1""]
}";
ConditionsBusinessObject fromV2 = JsonHandler.Parse(v2);
Assert.AreEqual(3, fromV2.Conditions.Count);
Assert.AreEqual("A < B", fromV2.Conditions[0]);
Assert.AreEqual("B = C", fromV2.Conditions[1]);
Assert.AreEqual("B < 1", fromV2.Conditions[2]);
}
在一个普通的现实世界应用程序中,//See what I've done here? 部分是您必须完成所有转换工作的地方。我在那里没有做任何聪明的事情,我只是将单个 condition 包装到一个列表中,以使其与 current 业务对象兼容。正如您可能猜到的那样,随着应用程序的发展,这可能会爆炸。软件工程 SE 中的 This answer 在版本化 JSON 数据背后的理论中有更多详细信息,因此您可能需要查看一下以了解会发生什么。
关于读取到 JObject 然后转换为 dto 的性能影响的最后一句话是,我没有进行任何测量,但我预计它比解析两次要好。如果我发现这不是真的,我会相应地更新答案。