c# - JSON (JObject) 到 C# 对象:无法打印 Pusher 接收到的数据
问题描述
我正在使用 Pusher 来实现实时通信。
这是我从推送器获取数据的函数:
private void PusherOnConnected(object sender)
{
Debug.Log("Connected");
channel.Bind("my-event", (dynamic data) =>
{
Debug.Log("my-event received");
Debug.Log(data.GetType().ToString());
Debug.Log(((JObject)data).ToString()); // <-- last line logged
// See EDIT to see what lines have been added
});
}
当我像这样从推送器发送事件时:
{
"foo": "bar"
}
我无法从 Unity 打印。以下是日志:
my-event received
Newtonsoft.Json.Linq.JObject
{
"event": "my-event",
"data": "{\r\n \"foo\": \"bar\"\r\n}",
"channel": "my-channel"
}
我正在尝试使用该方法将其放入 C# 对象中JObject.ToObject<>()
,但它不起作用。
- 因为 JSON 的键之一具有名称
event
,所以此名称不能是 C# 对象的属性 - 我知道
event
并且channel
会是一种string
类型,但是 的类型是data
什么?
dynamic data
如果知道显然是 a ,您将如何将此变量转换为对象JObject
?
编辑
我尝试按照@derHugo 的建议进行操作,但它仍然不想打印 C# 属性:
PusherEvent.cs
using Newtonsoft.Json;
using System;
[Serializable]
public class PusherEvent
{
[JsonProperty("event")]
public string theEvent;
public string channel;
public Data data;
}
[Serializable]
public class Data
{
public string foo;
}
在接收推送事件的方法内部(我没有同时尝试 1 和 2):
PusherEvent pe = ((JObject)data).ToObject<PusherEvent>(); // 1
PusherEvent pe = JsonConvert.DeserializeObject<PusherEvent>(data); // 2
Debug.Log(pe.channel);
这是我的日志: 如您所见,它不会记录通道属性,也不会抛出任何错误......
编辑2:完整代码
PusherManager.cs
using System;
using System.Threading.Tasks;
using JetBrains.Annotations;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
using PusherClient;
using UnityEngine;
public class PusherManager : MonoBehaviour
{
public static PusherManager instance = null;
private Pusher pusher;
private Channel channel;
async Task Start()
{
if (instance == null)
{
instance = this;
}
else if (instance != this)
{
Destroy(gameObject);
}
DontDestroyOnLoad(gameObject);
await InitialisePusher();
}
private async Task InitialisePusher()
{
if (pusher == null)
{
pusher = new Pusher("<my-secret-key>", new PusherOptions()
{
Cluster = "eu",
Encrypted = true
});
pusher.Error += OnPusherOnError;
pusher.ConnectionStateChanged += PusherOnConnectionStateChanged;
pusher.Connected += PusherOnConnected;
channel = await pusher.SubscribeAsync("my-channel");
channel.Subscribed += OnChannelOnSubscribed;
await pusher.ConnectAsync();
}
}
private void PusherOnConnected(object sender)
{
Debug.Log("Connected");
channel.Bind("my-event", (dynamic data) =>
{
Debug.Log("my-event received");
Debug.Log(data.GetType().ToString());
Debug.Log(((JObject)data).ToString());
PusherEvent pe = ((JObject)data).ToObject<PusherEvent>();
// PusherEvent pe = JsonConvert.DeserializeObject<PusherEvent>(((JObject)data).ToString());
Debug.Log(pe.channel);
});
}
private void PusherOnConnectionStateChanged(object sender, ConnectionState state)
{
Debug.Log("Connection state changed");
}
private void OnPusherOnError(object s, PusherException e)
{
Debug.Log("Errored");
}
private void OnChannelOnSubscribed(object s)
{
Debug.Log("Subscribed");
}
async Task OnApplicationQuit()
{
if (pusher != null)
{
await pusher.DisconnectAsync();
}
}
}
解决方案
我终于设法做到了。问题实际上是根对象是 aJObject
而data
这个对象的属性是 a string
, ~~ 而不是另一个JObject
~~:
// PusherManager.cs
// ...
PEvent<FireworkInfo> pe = new PEvent<FireworkInfo>(pusherEvent);
Debug.Log(pe);
// ...
// PEvent.cs
using Newtonsoft.Json.Linq;
using System;
[Serializable]
public class PEvent<T>
{
public string @event;
public string channel;
public T data;
public PEvent(dynamic pusherEvent)
{
this.@event = pusherEvent["event"];
this.channel = pusherEvent["channel"];
this.data = JObject.Parse((string)pusherEvent["data"]).ToObject<T>();
}
public override string ToString()
{
return data.ToString();
}
}
解决方案
对于等于 c# 关键字的字段名称,您可以使用逐字字符串 ( @
)并将其命名
public string @event;
或者,您也可以随意命名该字段,但添加一个相应[JsonProperty]
属性以明确告诉 JSON.NET 相应字段如何在 JSON 中命名
[JsonProperty("event")]
public string Event;
您展示的data
将只是一个嵌套类
[Serializable]
public class Data
{
public string foo;
}
所以你的课应该看起来像
[Serializable]
public class Response
{
public string @event;
// or
//[JsonProperty("event)]
//public string Event;
public Data data;
public string channel;
}
如果您实际上需要它,dynamic
因为从那里接收不同的数据结构,Pusher
那么您应该检查将JSON 反序列化为 C# 动态对象?特别是例如这个答案
dynamic stuff = JObject.Parse("{ 'Name': 'Jon Smith', 'Address': { 'City': 'New York', 'State': 'NY' }, 'Age': 42 }"); string name = stuff.Name; string address = stuff.Address.City;
为此,您仍然需要知道字段的名称。
或者看到这个答案,您将为您的字段创建一个Dictionary
,您可以首先检查ContainsKey
某个字段是否存在于接收到的数据结构中。
推荐阅读
- workflow - Netflix Conductor:如何获得一组基于时间范围的工作流
- ruby-on-rails - 如何使用 ransack gem 根据模型的实例方法对表进行排序?
- c# - 如何统一更改游戏对象的颜色?
- c# - C# 9 记录的自定义相等检查
- php - 正确的 Laravel 方法来获得基于两个表的关系
- c# - 在 Json 模型中正确使用自定义转换器作为动态 JsonProperty 名称
- reactjs - 为什么我不能将我的组件导入我的应用程序?
- laravel - Laravel 请求验证错误。必需的错误
- python - 套接字编程,打印功能在服务器代码上不起作用
- go - 如何使用 protobuf 二进制文件过滤 PUB/SUB ( ZeroMQ )?