第三方类型的Json.NET自定义序列化/反序列化 [英] Json.NET custom serialization/deserialization of a third party type

查看:45
本文介绍了第三方类型的Json.NET自定义序列化/反序列化的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我想将OpenTK库的Vector与JSON相互转换.我认为它的工作方式只是制作一个自定义JsonConverter,所以我这样做了:

I want to converts Vectors of the OpenTK library to and from JSON. The way I thought it worked is just making a custom JsonConverter, so I did this:

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

    public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
    {
        var obj = JToken.Load(reader);
        if (obj.Type == JTokenType.Array)
        {
            var arr = (JArray)obj;
            if (arr.Count == 4 && arr.All(token => token.Type == JTokenType.Float))
            {
                return new Vector4(arr[0].Value<float>(), arr[1].Value<float>(), arr[2].Value<float>(), arr[3].Value<float>());
            }
        }
        return null;
    }

    public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
    {
        var vector = (Vector4)value;
        writer.WriteStartArray();
        writer.WriteValue(vector.X);
        writer.WriteValue(vector.Y);
        writer.WriteValue(vector.Z);
        writer.WriteValue(vector.W);
        writer.WriteEndArray();
    }
}

现在,写"部分对我来说很简单(我认为?).当序列化程序遍历对象时,如果遇到CanConvert方法以true响应的对象,它将使我的自定义序列化程序将其转换为JSON.那行得通.

Now, the Write part is pretty straight forward to me (I think?). When the serializer goes through objects, if it encounters one that the CanConvert method responds to with true, it lets my custom serializer to convert it to JSON. And that works.

我没有真正得到的是另一种方式.由于用JSON文字编写时无法知道某物是什么类型,因此我认为我必须自己分析该对象并确定其是否实际上是Vector对象. 我编写的代码有效,但是如果检查失败,我不知道该怎么办.我如何告诉反序列化器这不是我知道如何翻译的对象之一,而是应该将其作为默认对象?

What I don't really get is the other way. Since there's no way to know what type something is when it's just written in literals in JSON, I thought I have to analyse the object myself and determine if it's in fact the Vector object. The code I've written works, but I don't know what to do if the check fails. How do I tell the deserializer that this isn't one of the objects that I know how to translate and that it should do it's default thing on it?

在整个过程中我是否缺少某些东西?

Am I missing something in how the whole thing works?

推荐答案

在反序列化期间,Json.Net会查看您要反序列化的类,以确定要创建的类型,并扩展确定是否调用转换器. .因此,如果您反序列化为具有Vector4属性的类,则将调用您的转换器.如果将反序列化为dynamicobjectJObject之类的模糊对象,则Json.Net将不知道调用您的转换器,因此反序列化的对象层次结构将不包含任何Vector4实例.

During deserialization, Json.Net looks at the classes that you are deserializing into in order to determine what types to create, and by extension, whether to call your converter. So, if you deserialize into a class that has a Vector4 property, your converter will be called. If you deserialize into something nebulous like dynamic or object or JObject, then Json.Net will not know to call your converter, and therefore the deserialized object hierarchy will not contain any Vector4 instances.

让我们举一个简单的例子来使这个概念更加清晰.说我们有这个JSON:

Let's take a simple example to make this concept more clear. Say we have this JSON:

{
    "PropA": [ 1.0, 2.0, 3.0, 4.0 ],
    "PropB": [ 5.0, 6.0, 7.0, 8.0 ]
}

很明显,上述JSON 中的'PropA'和'PropB'都可以表示Vector4(或至少我从您的转换器代码中推断为Vector4的东西-实际上不熟悉OpenTK库).但是,正如您所注意到的那样,JSON中没有任何类型信息,它指出任一属性都应为Vector4.

Clearly, both 'PropA' and 'PropB' in the above JSON could represent a Vector4 (or at least what I infer to be a Vector4 from your converter code-- I am not actually familiar with the OpenTK library). But, as you noticed, there is no type information in the JSON that says that either property should be a Vector4.

让我们尝试使用您的转换器将JSON反序列化为以下类.在这里,PropA必须包含Vector4或null,因为它是强类型的,而PropB可以是任何东西.

Let's try to deserialize the JSON into the following class using your converter. Here, PropA must contain a Vector4 or null since it is strongly typed, while PropB could be anything.

public class Tester
{
    public Vector4 PropA { get; set; }
    public object PropB { get; set; }
}

这是测试代码:

class Program
{
    static void Main(string[] args)
    {
        string json = @"
        {
            ""PropA"": [ 1.0, 2.0, 3.0, 4.0 ],
            ""PropB"": [ 5.0, 6.0, 7.0, 8.0 ]
        }";

        try
        {
            Tester t = JsonConvert.DeserializeObject<Tester>(json),
                                              new VectorConverter());

            DumpObject("PropA", t.PropA);
            DumpObject("PropB", t.PropB);
        }
        catch (Exception ex)
        {
            Console.WriteLine(ex.GetType().Name + ": " + ex.Message);
        }
    }

    static void DumpObject(string prop, object obj)
    {
        if (obj == null)
        {
            Console.WriteLine(prop + " is null");
        }
        else
        {
            Console.WriteLine(prop + " is a " + obj.GetType().Name);
            if (obj is Vector4)
            {
                Vector4 vector = (Vector4)obj;
                Console.WriteLine("   X = " + vector.X);
                Console.WriteLine("   Y = " + vector.Y);
                Console.WriteLine("   Z = " + vector.Z);
                Console.WriteLine("   W = " + vector.W);
            }
            else if (obj is JToken)
            {
                foreach (JToken child in ((JToken)obj).Children())
                {
                    Console.WriteLine("   (" + child.Type + ") " 
                                             + child.ToString());
                }
            }
        }
    }
}

// Since I don't have the OpenTK library, I'll use the following class
// to stand in for `Vector4`.  It should look the same to your converter.

public class Vector4
{
    public Vector4(float x, float y, float z, float w)
    {
        X = x;
        Y = y;
        Z = z;
        W = w;
    }

    public float W { get; set; }
    public float X { get; set; }
    public float Y { get; set; }
    public float Z { get; set; }
}

当我运行测试代码时,这是我得到的输出:

When I run the test code, here is the output I get:

PropA is a Vector4
   X = 1
   Y = 2
   Z = 3
   W = 4
PropB is a JArray
   (Float) 5
   (Float) 6
   (Float) 7
   (Float) 8

因此,您可以看到,对于PropA,Json.Net使用转换器创建了Vector4实例(否则我们将得到一个JsonSerializationException),而对于PropB,它并没有(否则,我们将在输出中看到PropB is a Vector4.

So you can see, for PropA, Json.Net used the converter to create the Vector4 instance (otherwise we would have gotten a JsonSerializationException), while for PropB, it did not (otherwise, we would have seen PropB is a Vector4 in the output).

对于问题的第二部分,如果给转换器提供的JSON不是预期的,该怎么办.您有两种选择-像执行操作一样返回null或引发异常(例如JsonSerializationException).如果正在调用您的转换器,则您知道Json.Net正在尝试填充Vector4对象.如果不是,则将不会调用您的转换器.因此,如果由于JSON错误而无法填充它,则必须确定Vector4为null是可接受的,还是更好地进行错误输出.这是一个设计决定,取决于您要在项目中尝试做什么.

As for the second part of your question, what to do if your converter is given JSON that is not what it is expecting. You have two choices-- return null, like you are doing, or throw an exception (such as a JsonSerializationException). If your converter is being called, you know that Json.Net is trying to populate a Vector4 object. If it were not, then your converter would not have been called. So, if you can't populate it because the JSON is wrong, you have to decide whether it is acceptable that the Vector4 be null, or is it better to error out. It is a design decision that depends on what you are trying to do in your project.

我已经清楚地解释了吗?

Have I explained that clearly?

这篇关于第三方类型的Json.NET自定义序列化/反序列化的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

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