От JSON (JObject) до C# Object: невозможно распечатать данные, полученные Pusher - PullRequest
0 голосов
/ 19 июня 2020

Я использую 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
        });
    }

Когда я отправляю событие из pusher, например это:

{
  "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<>(), но он не работает.

  1. Поскольку один из ключей JSON имеет имя event, это имя не может быть свойством объекта C#
  2. Я знаю, что event и channel будет string типа, но какой будет тип data?

Как бы вы преобразовали эту dynamic data переменную в объект, зная, что это, по-видимому, JObject?

РЕДАКТИРОВАТЬ

Я пытался сделать то, что предлагает @ derHu go, но он все еще не хочет печатать свойство 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;
}

Внутри метода, принимающего событие pusher (1 и 2 одновременно не пробовал):

            PusherEvent pe = ((JObject)data).ToObject<PusherEvent>();          // 1
            PusherEvent pe = JsonConvert.DeserializeObject<PusherEvent>(data); // 2
            Debug.Log(pe.channel);

Вот мои логи: enter image description here Как видите, это не регистрирует свойство канала и не генерирует никаких ошибок ...

EDIT 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();
        }
    }
}

РЕШЕНИЕ

Мне наконец удалось это сделать . Проблема заключалась в том, что объект root был JObject, тогда как свойство data этого объекта было 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();
    }
}

1 Ответ

1 голос
/ 19 июня 2020

Для имен полей, которые равны c# ключевым словам, вы можете использовать дословную строку (@) и назвать ее

public string @event;

См., Например, объект для десериализации имеет a C# ключевое слово

Или, альтернативно, вы также можете назвать поле как хотите, но добавить соответствующий атрибут [JsonProperty], чтобы явно указать JSON. NET как соответствующее поле названо в JSON

[JsonProperty("event")]
public string Event;

См., например, Десериализация JSON ответов, которые содержат атрибуты, конфликтующие с ключевыми словами

Показанный вами 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# динамический 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, присутствует ли какое-либо поле в полученной структуре данных.

...