将 JSON 字段升级为 class 结构的最佳方法

Best way to upgrade JSON field to a class structure

只是想知道是否有人知道将 JSON 结构反序列化升级到新的 class 类型的最佳方法。

进一步解释遗留值是

        public string author;

现在已在 api 中更新为以下

 public class Author
{
    public string name;
    public string email;
    public string url;
}

public Author author;

所以现在我遇到了一个问题,即任何遗留数据都没有正确反序列化为这个,因为它曾经是一个字符串,现在是 class.

我目前的解决方案是,如果反序列化失败,则将其转换为具有旧结构的 class,然后使用它进入新结构,但我觉得必须有更好的方法作为过程的一部分,将旧的 sting 值转换为新的 class 值。

谢谢

编辑-1:

好的,我已经通过下面的转换器取得了一些进展

public class AuthorConverter : JsonConverter
{
    public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
    {
        Author user = (Author)value;
        writer.WriteValue(user);
    }

    public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
    {
        Author author = new Author();

        Debug.Log(objectType + "  " + reader.Value);
        if (reader.TokenType == JsonToken.String)
        {
            author.name = (string) reader.Value;
        }
        else if(reader.TokenType == JsonToken.StartObject)
        {
            try
            {
                JObject jObject = JObject.Load(reader);

                if (jObject.TryGetValue("name", out JToken name))
                {
                    author.name = name.Value<string>();
                }
                if (jObject.TryGetValue("email", out JToken email))
                {
                    author.email = email.Value<string>();
                }

                if (jObject.TryGetValue("url", out JToken url))
                {
                    author.url = url.Value<string>();
                }

            }
            catch (Exception e)
            {
                UnityEngine.Debug.Log(e);
                throw;
            }

        }
        return author;
    }

似乎一切正常,但感觉必须 1 乘 1 地获取值并转换有点繁琐,我尝试使用 jObject.ToObject 方法但似乎导致无限循环。无论哪种方式,它的工作,但我相信有更好的方法,所以仍然开放的想法。

由于您的 Author 具有默认(无参数)构造函数,因此您可以避免使用 JsonSerializer.Populate(JsonReader, Object). And to avoid having to write your own WriteJson() method, override CanWrite 和 return false 手动填充每个 属性。

因此您的转换器可以重写如下:

public class AuthorConverter : JsonConverter
{
    public override bool CanConvert(Type objectType) { return objectType == typeof(Author); }

    public override bool CanWrite { get { return false; } }

    public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
    {
        throw new NotImplementedException();
    }

    public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
    {
        try
        {
            if (reader.MoveToContentAndAssert().TokenType == JsonToken.Null)
                return null; // Or throw an exception if you don't want to allow null.
            else if (reader.TokenType == JsonToken.String)
                return new Author { name = (string) reader.Value };
            else
            {
                var author = new Author();
                serializer.Populate(reader, author);
                return author;
            }           
        }
        catch (Exception ex)
        {
            UnityEngine.Debug.Log(ex);
            throw;
        }
    }
}

public static partial class JsonExtensions
{
    // Skip past any comments to the next content token, asserting that the file was not truncated.
    public static JsonReader MoveToContentAndAssert(this JsonReader reader)
    {
        if (reader == null)
            throw new ArgumentNullException();
        if (reader.TokenType == JsonToken.None)       // Skip past beginning of stream.
            reader.ReadAndAssert();
        while (reader.TokenType == JsonToken.Comment) // Skip past comments.
            reader.ReadAndAssert();
        return reader;
    }

    // Read (advance to) the next token, asserting that the file was not truncated.
    public static JsonReader ReadAndAssert(this JsonReader reader)
    {
        if (reader == null)
            throw new ArgumentNullException();
        if (!reader.Read())
            throw new JsonReaderException("Unexpected end of JSON stream.");
        return reader;
    }
}

备注:

  • Json.NET supports comments in JSON 尽管它们不是 JSON 标准的一部分。序列化程序会忽略注释,但在编写转换器时必须手动跳过它们。

  • JsonReader 将对大多数类型的格式错误的 JSON(例如 {"a":"b"])抛出异常,但不会对截断的文件抛出异常,因此转换器不应假设预期的令牌已成功读取。

  • 另见 and .

演示 fiddle here.