2015-11-27 208 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