将 JSON 字段升级为类结构的最佳方法 [英] Best way to upgrade JSON field to a class structure

查看:14
本文介绍了将 JSON 字段升级为类结构的最佳方法的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

Just wondering if anyone knows of the best way to upgrade a JSON structure Deserialisation to a new class type.

进一步解释遗留值是

        public string author;

这已在 api 中更新为以下内容

this has now been updated in the api to the following

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

public Author author;

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

So now I have an issue where any legacy data does not deserialize into this correctly as it used to be a string and now its a class.

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

My current solution is if it fails to deserialize then to do it into a class that had the old structure and then use this to go into the new one, but i feel there must be a better way to cast the old sting value into the new class value as part of the process.

谢谢

EDIT-1:

好的,我在下面的转换器方面取得了一些进展

Ok i have made some headway with a converter below

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 方法,但似乎会导致无限循环.无论哪种方式都有效,但我确信有更好的方法,所以仍然欢迎想法.

Appears to all be working, but feels a bit fiddly to have to get the values 1 by 1 and convert over, i tried using the jObject.ToObject method but appeared to cause an infinite loop. Either way its working, but im sure there is a better way, so still open for ideas.

推荐答案

由于您的 Author 具有默认(无参数)构造函数,您可以避免使用 JsonSerializer.Populate(JsonReader, Object).为了避免编写自己的 WriteJson() 方法,请覆盖 CanWrite 并返回 false.

Since your Author has a default (parameterless) constructor, you can avoid having to populate each property manually by using JsonSerializer.Populate(JsonReader, Object). And to avoid having to write your own WriteJson() method, override CanWrite and return false.

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

Thus your converter can be rewritten as follows:

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 支持 JSON 格式的评论它们不属于 JSON 标准的事实.序列化程序会忽略注释,但在编写转换器时必须手动跳过它们.

  • Json.NET supports comments in JSON despite the fact that they are not part of the JSON standard. The serializer ignores comments but they must be manually skipped when writing a converter.

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

JsonReader will throw an exception on most types of malformed JSON (e.g {"a":"b"]) but will not throw an exception for a truncated file, so converters should not assume that expected tokens are read successfully.

另请参阅使用 JsonConverter 的 Json.NET 自定义序列化 - 如何获取默认"行为如何在自定义 JsonConverter 中使用默认序列化.

演示小提琴这里.

这篇关于将 JSON 字段升级为类结构的最佳方法的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆