所以我有一个客户端-服务器应用程序,它使用这个类进行通信,它包含一个对象,所以我可以在服务器和客户端之间发送任何类型的数据:
public class comObj
{
public eDisconnectedReason dcReason;
public object payload;
}
在通过套接字发送之前,我将使用JSon.Net对其进行序列化,例如:
string jsonString = JsonConvert.SerializeObject((new Common.comObj() { dcReason = Server.disconnectedReason, payload = Data }), Formatting.None);
现在,服务器接收到的正是客户端发送的字符串:
sent string: "{"dcReason":4,"payload":{"msg":"hi"}}"
received string: "{"dcReason":4,"payload":{"msg":"hi"}}"
然而,当我试图将接收到的字符串反序列化为原始comObj:时
Common.comObj rcvdObj = JsonConvert.DeserializeObject<Common.comObj>(rcvdString);
rcvdObj.payload的类型为Newtonsoft.Json.Linq.JObject,而不是object。
让我们从考虑您的JSON输入开始:
{
"dcReason": 4,
"payload": {
"msg": "hi"
}
}
使用Json.NET,您有两种反序列化Json数据的关键方法。您可以:
- 将其反序列化为特定的具体类型
- 您可以将其反序列化为通用
JToken
类型。(在您的案例中,它实例化了JObject
——JToken
的子类——因为JSON.Net识别出JSON输入指定了一个对象,而不是基元类型或数组)
在您的案例中,实际上您最终采用了两种方法的混合。由于您为根对象指定了特定的类型,因此它返回了comObj
的实例。由于您只指定了object
作为属性payload
的类型,Json.NET尽了最大努力,简单地恢复到选项2),并为您提供了JObject
的实例,其中包含msg
等数据。
你有两种选择来解决你的问题。您可以:
- 将
payload
属性询问为JObject
,就像如果没有使用选项1),则必须对整个JSON主体执行的操作一样 - 定义一个具体类型来表示
payload
属性。我强烈推荐这种方法,因为它更安全,也更容易使用
为了实现前者,您可以使用o["msg"]
之类的功能——本质上就像字典一样。
为了实现后者——我建议这样做——只需为payload
定义一个类型。换句话说,将您的代码更改为:
public class comObj
{
public eDisconnectedReason dcReason;
public Payload payload;
}
public class Payload
{
public string msg { get; set; }
}
现在,当您反序列化JSON时,您将能够使用以下语法:
Console.WriteLine(rcvdObj.payload.msg);
而且——重要的是——如果您稍后决定将JSON负载中的msg
重命名为message
,您将能够正确地将负载的属性msg
重构为message
,并期望所有用法都得到修复。当使用字符串时,这显然不那么健壮。