首页 > 解决方案 > 如何将 json 反序列化为结构?

问题描述

我有一个这样的类映射:

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 字符串?

标签: c#json.netdeserialization

解决方案


另一种解决方案可能是利用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版本
  • 公共字段在抽象基类中定义

现在,您可以使用这两个版本化的类来定义 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");
}

推荐阅读