如何将 json 反序列化为结构?
How Can I deserialize a json into a structure?
我有一个这样的 class 映射:
public class Settings
{
[JsonProperty("id")]
public string Id { get; set; }
[JsonProperty("type")]
public string Type { get; set; }
[JsonProperty("content")]
public ContentStructure Content { get; set; }
}
public struct ContentStructure
{
public Content ContentClass;
public string ContentString;
public static implicit operator ContentStructure(Content content) => new ContentStructure { ContentClass = content };
public static implicit operator ContentStructure(string @string) => new ContentStructure { ContentString = @string };
}
public class Content
{
[JsonProperty("id")]
public string Id { get; set; }
[JsonProperty("duration")]
public long Duration { get; set; }
}
当我尝试反序列化以下 JSON 字符串时:
{
"id": "any_id",
"type": "any_type",
"content": {
"id": "any_id",
"duration": 1000
}
}
我总是使用 属性 settings.Content.ContentClass null 获取反序列化设置对象,但每当我的 JSON 字符串具有 属性 "content"
作为字符串(而不是对象)结构字段 ContentString
正确。我做错了什么?我怎样才能正确转换上面的 JSON 字符串?
输入的 json 不符合您的格式。
如果您改用 json,
{
"id": "any_id",
"type": "any_type",
"content": {
"ContentClass" : {
"id": "any_id",
"duration": 1000
}
}
}
这样就可以了。
settings.Content.ContentClass 是三层,而你的是 json 两层 (settings.Content)。所以在“content”之后,它正在寻找 ContentStructure 没有这两个字段的 id 和 duration。
我的推理是当它遇到一个值类型(如{“field”:“value}”)时,它会寻找值类型,如string,int或double。当它遇到json类型时(如 {"field" : {another json here} }),它将查找 class 或 struct.
使用 Custom JsonConverter。根据需要修改。
[JsonConverter(typeof(ContentStructureConverter))]
public struct ContentStructure
{
public Content ContentClass;
public string ContentString;
public static implicit operator ContentStructure(Content content) => new ContentStructure { ContentClass = content };
public static implicit operator ContentStructure(string @string) => new ContentStructure { ContentString = @string };
}
public class ContentStructureConverter : JsonConverter
{
public override bool CanConvert(Type objectType)
{
return objectType == typeof(ContentStructure);
}
public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
{
ContentStructure contentStruct;
if (reader.ValueType == typeof(string))
contentStruct = reader.Value as string;
else
contentStruct = serializer.Deserialize<Content>(reader);
return contentStruct;
}
public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
{
ContentStructure? contentStruct = value as ContentStructure?;
if (contentStruct.HasValue && contentStruct.Value.ContentClass != null)
serializer.Serialize(writer, contentStruct.Value.ContentClass);
else
serializer.Serialize(writer, contentStruct.Value.ContentString);
}
}
另一种解决方案可能是利用 JsonSchema
首先让我们重新定义您的数据模型:
public abstract class Settings
{
[JsonProperty("id")]
public string Id { get; set; }
[JsonProperty("type")]
public string Type { get; set; }
}
public class SettingsV1 : Settings
{
[JsonProperty("content")]
public string Content { get; set; }
}
public class SettingsV2 : Settings
{
[JsonProperty("content")]
public Content Content { get; set; }
}
public class Content
{
[JsonProperty("id")]
public string Id { get; set; }
[JsonProperty("duration")]
public long Duration { get; set; }
}
- 不用中间人 (
ContentStructure
) 而不是你可以有两个单独的 Settings
版本
- 公共字段在抽象基中定义class
现在,您可以使用这两个版本化的 classes 来定义 json 模式:
private static JSchema schemaV1;
private static JSchema schemaV2;
//...
var generator = new JSchemaGenerator();
schemaV1 = generator.Generate(typeof(SettingsV1));
schemaV2 = generator.Generate(typeof(SettingsV2));
最后,您需要做的就是在使用正确的类型调用 DeserializeObject
之前进行初步检查:
Settings settings = null;
var semiParsed = JObject.Parse(json);
if (semiParsed.IsValid(schemaV1))
{
settings = JsonConvert.DeserializeObject<SettingsV1>(json);
}
else if (semiParsed.IsValid(schemaV2))
{
settings = JsonConvert.DeserializeObject<SettingsV2>(json);
}
else
{
throw new NotSupportedException("The provided json format is not supported");
}
我有一个这样的 class 映射:
public class Settings
{
[JsonProperty("id")]
public string Id { get; set; }
[JsonProperty("type")]
public string Type { get; set; }
[JsonProperty("content")]
public ContentStructure Content { get; set; }
}
public struct ContentStructure
{
public Content ContentClass;
public string ContentString;
public static implicit operator ContentStructure(Content content) => new ContentStructure { ContentClass = content };
public static implicit operator ContentStructure(string @string) => new ContentStructure { ContentString = @string };
}
public class Content
{
[JsonProperty("id")]
public string Id { get; set; }
[JsonProperty("duration")]
public long Duration { get; set; }
}
当我尝试反序列化以下 JSON 字符串时:
{
"id": "any_id",
"type": "any_type",
"content": {
"id": "any_id",
"duration": 1000
}
}
我总是使用 属性 settings.Content.ContentClass null 获取反序列化设置对象,但每当我的 JSON 字符串具有 属性 "content"
作为字符串(而不是对象)结构字段 ContentString
正确。我做错了什么?我怎样才能正确转换上面的 JSON 字符串?
输入的 json 不符合您的格式。
如果您改用 json,
{
"id": "any_id",
"type": "any_type",
"content": {
"ContentClass" : {
"id": "any_id",
"duration": 1000
}
}
}
这样就可以了。
settings.Content.ContentClass 是三层,而你的是 json 两层 (settings.Content)。所以在“content”之后,它正在寻找 ContentStructure 没有这两个字段的 id 和 duration。
我的推理是当它遇到一个值类型(如{“field”:“value}”)时,它会寻找值类型,如string,int或double。当它遇到json类型时(如 {"field" : {another json here} }),它将查找 class 或 struct.
使用 Custom JsonConverter。根据需要修改。
[JsonConverter(typeof(ContentStructureConverter))]
public struct ContentStructure
{
public Content ContentClass;
public string ContentString;
public static implicit operator ContentStructure(Content content) => new ContentStructure { ContentClass = content };
public static implicit operator ContentStructure(string @string) => new ContentStructure { ContentString = @string };
}
public class ContentStructureConverter : JsonConverter
{
public override bool CanConvert(Type objectType)
{
return objectType == typeof(ContentStructure);
}
public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
{
ContentStructure contentStruct;
if (reader.ValueType == typeof(string))
contentStruct = reader.Value as string;
else
contentStruct = serializer.Deserialize<Content>(reader);
return contentStruct;
}
public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
{
ContentStructure? contentStruct = value as ContentStructure?;
if (contentStruct.HasValue && contentStruct.Value.ContentClass != null)
serializer.Serialize(writer, contentStruct.Value.ContentClass);
else
serializer.Serialize(writer, contentStruct.Value.ContentString);
}
}
另一种解决方案可能是利用 JsonSchema
首先让我们重新定义您的数据模型:
public abstract class Settings
{
[JsonProperty("id")]
public string Id { get; set; }
[JsonProperty("type")]
public string Type { get; set; }
}
public class SettingsV1 : Settings
{
[JsonProperty("content")]
public string Content { get; set; }
}
public class SettingsV2 : Settings
{
[JsonProperty("content")]
public Content Content { get; set; }
}
public class Content
{
[JsonProperty("id")]
public string Id { get; set; }
[JsonProperty("duration")]
public long Duration { get; set; }
}
- 不用中间人 (
ContentStructure
) 而不是你可以有两个单独的Settings
版本 - 公共字段在抽象基中定义class
现在,您可以使用这两个版本化的 classes 来定义 json 模式:
private static JSchema schemaV1;
private static JSchema schemaV2;
//...
var generator = new JSchemaGenerator();
schemaV1 = generator.Generate(typeof(SettingsV1));
schemaV2 = generator.Generate(typeof(SettingsV2));
最后,您需要做的就是在使用正确的类型调用 DeserializeObject
之前进行初步检查:
Settings settings = null;
var semiParsed = JObject.Parse(json);
if (semiParsed.IsValid(schemaV1))
{
settings = JsonConvert.DeserializeObject<SettingsV1>(json);
}
else if (semiParsed.IsValid(schemaV2))
{
settings = JsonConvert.DeserializeObject<SettingsV2>(json);
}
else
{
throw new NotSupportedException("The provided json format is not supported");
}