我有一个像这样的类映射:
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字符串?
另一个解决方案是使用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; }
}
- 你可以有两个单独的
Settings
版本,而不是有一个中间人(ContentStructure
) 公共字段在抽象基类中定义。
现在,您可以使用这两个版本化的类来定义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");
}
使用自定义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);
}
}
输入的json不符合您的格式。
如果你使用这个json,
{
"id": "any_id",
"type": "any_type",
"content": {
"ContentClass" : {
"id": "any_id",
"duration": 1000
}
}
}
这样就可以了。
settings.Content。ContentClass是三层的,但是你的json是两层的(settings.Content)。所以在"content"之后,它正在寻找id和duration,而ContentStructure没有这两个字段。
我的推理是当它遇到一个值类型(比如{"field": "value}),它将查找值类型,如string、int或double。当它遇到json类型(比如{"field":{这里另一个json}}),它将查找类或结构。