簡體   English   中英

Json.NET自定義序列化/反序列化第三方類型

[英]Json.NET custom serialization/deserialization of a third party type

我想將OpenTK庫的Vector轉換為JSON和從JSON轉換。 我認為它的工作方式只是制作一個自定義的JsonConverter,所以我這樣做:

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();
    }
}

現在,Write部分對我很直接(我想?)。 當序列化程序遍歷對象時,如果遇到CanConvert方法響應為true的對象,它會讓我的自定義序列化程序將其轉換為JSON。 這很有效。

我沒有真正得到的是另一種方式。 因為當用JSON中的文字書寫時,沒有辦法知道什么類型的東西,我想我必須自己分析對象並確定它是否實際上是Vector對象。 我編寫的代碼有效,但如果檢查失敗,我不知道該怎么辦。 我如何告訴反序列化器這不是我知道如何翻譯的對象之一,它應該在它上面做默認的事情?

我錯過了整個事情的工作原理嗎?

在反序列化期間,Json.Net會查看要反序列化的類,以確定要創建的類型,以及擴展名,是否調用轉換器。 因此,如果將反序列化為具有Vector4屬性的類,則將調用轉換器。 如果你反序列化為像dynamicobjectJObject這樣模糊不清的東西,那么Json.Net將不知道調用你的轉換器,因此反序列化的對象層次結構將不包含任何Vector4實例。

讓我們舉個簡單的例子來說明這個概念。 假設我們有這個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

讓我們嘗試使用您的轉換器將JSON反序列化到以下類中。 這里, PropA必須包含一個Vector4或null,因為它是強類型的,而PropB可以是任何東西。

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; }
}

當我運行測試代碼時,這是我得到的輸出:

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輸出中PropB is a Vector4 )。

至於你問題的第二部分,如果你的轉換器被賦予了不符合預期的JSON,該怎么辦。 你有兩個選擇 - 像你一樣返回null,或拋出異常(例如JsonSerializationException)。 如果正在調用您的轉換器,您知道Json.Net正在嘗試填充Vector4對象。 如果不是,那么你的轉換器就不會被調用。 因此,如果由於JSON錯誤而無法填充它,則必須確定Vector4是否為空是否可接受,或者錯誤輸出是否更好。 這是一個設計決策,取決於您在項目中嘗試做什么。

我清楚地解釋了嗎?

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM