2015-11-27 211 views
0

我想序列化和反序列化客戶端和服務器之間發送的對象爲JSON。餘包從客戶端的所有消息在一個簡單的請求 - 對象看起來像這樣:JSON反序列化的對象列表

class Request 
{ 
    public string Command { get; set; } 
    public object[] Arguments { get; set; } 
} 

參數的陣列可以是所需的選擇的命令的任何類型的對象。然後在服務器上反序列化,並希望請求與Arguments數組中相同類型的對象完全相同。

我已經嘗試過.Net和Json.Net中包含的JavascriptSerialization,但是它們都在參數列表中有一些對象類型的麻煩。 字符串,整數和其他基本的東西很好地工作,但例如Guid總是在反序列化之後以字符串的形式彈出。

當使用Json.Net時,其他複雜對象變成「JObject」。(我從@jlvaquero得到了幫助。)

有沒有人有如何使反序列化儘可能正確的建議?

例子:https://dotnetfiddle.net/V3HKol

+0

試試這個https://dotnetfiddle.net/GSlwIR – jlvaquero

+0

@jlvaquero我已經更新了dotnetfiddle,所以你可以看到錯誤。 – einord

回答

1

您需要使用TypeNameHandling設置。

如果JSON字符串包含每個序列化對象中的運行時類型,那麼JSon.Net將它反序列化爲匹配運行時類型。

using System; 
using Newtonsoft.Json; 

public class Program 
{ 
    public static void Main() 
    { 
     Request r = new Request(); 
     r.Arguments[0] = new TestObject("111111"); 
     r.Arguments[1] = new TestObject("222222"); 

     string output = JsonConvert.SerializeObject(r, Formatting.Indented, new JsonSerializerSettings 
{ 
    TypeNameHandling = TypeNameHandling.All 
}); 
     Console.WriteLine(output); 
     Request deserializedr = JsonConvert.DeserializeObject<Request>(output, new JsonSerializerSettings 
{ 
    TypeNameHandling = TypeNameHandling.Auto 
}); 

     Console.WriteLine(deserializedr.Command); 
     Console.WriteLine(((TestObject)(deserializedr.Arguments[0])).Name); 
     Console.WriteLine(((TestObject)(deserializedr.Arguments[0])).ID); 
     Console.WriteLine(((TestObject)(deserializedr.Arguments[1])).Name); 
     Console.WriteLine(((TestObject)(deserializedr.Arguments[1])).ID); 
     Console.ReadKey(); 
    } 
} 
    public class Request 
{ 
     public Request(){ 
      Command = "boquepasa"; 
      Arguments = new Object[2]; 
     } 
    public string Command { get; set; } 
    public object[] Arguments { get; set; } 
} 

public class TestObject 
{ 
    public TestObject(string name) 
    { 
     ID = Guid.NewGuid(); 
     Name = name; 
    } 

    public string Name { get; set; } 
    public Guid ID { get; set; } 
} 

輸出:

{ 
    "$type": "Request, ConsoleApplication1", 
    "Command": "boquepasa", 
    "Arguments": { 
    "$type": "System.Object[], mscorlib", 
    "$values": [ 
     { 
     "$type": "TestObject, ConsoleApplication1", 
     "Name": "111111", 
     "ID": "739479b5-9034-451f-9b58-abcf4c7671f1" 
     }, 
     { 
     "$type": "TestObject, ConsoleApplication1", 
     "Name": "222222", 
     "ID": "f6ea82d5-fa3d-481d-812e-baf9fab49a86" 
     } 
    ] 
    } 
} 
boquepasa 
111111 
739479b5-9034-451f-9b58-abcf4c7671f1 
222222 
f6ea82d5-fa3d-481d-812e-baf9fab49a86 

如果你r.Arguments[2] = Guid.NewGuid() JSON.Net反序列化作爲String。我在Newtonsoft.Json repoisotry中打開了一個問題,當我們等待響應時,我分叉了原始github存儲庫,在Object Array支持中添加了Guid。我的回購是here和適用於這個特定的問題,但它沒有測試超出這個例子,所以使用它需要您自擔風險。

+0

但是,如果請求中的任何參數都是Guid,它將反序列化爲一個字符串,所以這不起作用。 – einord

+0

好的。現在我明白你了。當你做r.Arguments [2] = Guid.NewGuid(); Json.Net不包含運行時類型,然後在反序列化中失敗。 – jlvaquero

+1

@einord。我已經更新了答案。 JSON.Net不支持你現在需要的。 – jlvaquero

-1

您應該能夠以包括在Json.Net的JsonSerializerSettings設置爲

new JsonSerializerSettings 
{ 
    TypeNameHandling = TypeNameHandling.All 
} 

類型信息這將包括名爲$type JSON字符串,給出了一個新的屬性Json.Net提供反序列化對象的提示。

您需要在序列化的兩側使用此JsonSerializerSettings才能正常工作。

點擊此處瞭解詳情:http://www.newtonsoft.com/json/help/html/serializetypenamehandling.htm

class ExampleClass 
    { 
     public string StringProperty { get; set; } 
     public int IntProperty { get; set; } 
    } 

    class Program 
    { 
     static void Main(string[] args) 
     { 
      var objects = new object[] 
      { 
       new ExampleClass(), 
       new StringBuilder() 
      }; 

      var json = JsonConvert.SerializeObject(objects, new JsonSerializerSettings 
      { 
       TypeNameHandling = TypeNameHandling.All 
      }); 

      Console.WriteLine(json); 

      var deserializedObjects = JsonConvert.DeserializeObject(json, new JsonSerializerSettings 
      { 
       TypeNameHandling = TypeNameHandling.All 
      }); 

      foreach (var type in (object[])deserializedObjects) 
      { 
       Console.WriteLine(type.GetType()); 
      } 
      Console.ReadKey(); 
     } 
    } 

輸出

{ 
    "$type": "System.Object[], mscorlib", 
    "$values": [{ 
     "$type": "ConsoleApplication8.ExampleClass, ConsoleApplication8", 
     "StringProperty": null, 
     "IntProperty": 0 
    }, 
    { 
     "$type": "System.Text.StringBuilder, mscorlib", 
     "m_MaxCapacity": 2147483647, 
     "Capacity": 16, 
     "m_StringValue": "", 
     "m_currentThread": 0 
    }] 
} 

ConsoleApplication8.ExampleClass 
System.Text.StringBuilder 
+1

這不適用於對象數組。 JSON。Net將在Arguments數組的級別添加$ type屬性,而不是爲這個數組的每個元素添加。 –

+0

答案中提供的鏈接顯示它實際上會包含數組中所有元素的類型信息。 Json.Net不需要原語的類型信息,所以它不會包含它,但對於複雜類型,類型屬性將包含在內。 – gwoody1984

+0

剛剛添加了一個例子 – gwoody1984