2013-12-17 99 views
3

我想將OpenTK庫的向量轉換爲JSON或從JSON轉換爲向量。我的思維方式,它的工作只是把一個自定義JsonConverter,所以我這樣做:Json.NET自定義序列化/第三方類型的反序列化

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。那是有效的。

我真的不明白的是另一種方式。由於沒有辦法知道什麼類型的東西是用JSON文字寫成的,所以我認爲我必須自己分析對象,並確定它是否實際上是Vector對象。 我編寫的代碼有效,但如果檢查失敗,我不知道該怎麼辦。我如何告訴解串器,這不是我知道如何翻譯的對象之一,它應該做它的默認的東西呢?

我錯過了整個事情的工作方式嗎?

回答

4

在反序列化期間,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 ] 
} 

顯然,這兩種「PropA」和「PROPB」在上面的JSON 可以表示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,它沒有(否則,我們會看到輸出中爲)。

至於你的問題的第二部分,如果你的轉換器給予的JSON不是它所期待的,該怎麼辦。你有兩個選擇 - 返回null,就像你正在做的那樣,或者拋出一個異常(比如JsonSerializationException)。如果你的轉換器被調用,你知道Json.Net正在試圖填充一個Vector4對象。如果不是,那麼你的轉換器就不會被調用。因此,如果由於JSON錯誤而無法填充它,則必須決定Vector4爲空還是錯誤更好。這是一個設計決定,取決於你在你的項目中試圖做什麼。

我解釋清楚了嗎?

+0

你有,這是非常有道理的。非常感謝你 –