0

я раньше писал на js и всё было очень просто. У меня была функция onmessage, там я получал data, парсил ее и из нее доставал поле route. Потом это и был по сути роут. Вот так примерно.

const routes = {
  'route_1': () => {},
  'route_2': () => {}
}
...
ws.onmessage = (d) => {
 const data = JSON.Parse(d);
 if(routes[data.route]
   routes[data.route](data.data)
}

И это прекрасно работало в JS. Но как быть в C#? Я могу точно так же парсить json. Но я вот это не совсем понимаю. Там же надо создать класс, который описывает приходящие данные. Вроде такого:

class Data{
  public string route;
  public string data;
}
ws.onmessage = (d) => {
  var data = JSON.Parse<Data>();
}

Но мне же постоянно разные по структуре данные будут приходить. Для того чтоб знать какие надо сначала распарсить и посмотреть поле route. Как это обычно принято делать? Не могу найти.

2 Answers2

1

Но мне же постоянно разные по структуре данные будут приходить.

Ну и для каждого типа ты в любом пишешь код, на любом языке. Да, структуру на JS не описываешь, но обработчики приходится.


Что касается Websocket, Unity3D тут роли не играет, чисто C#.


Некоторые инструменты C# отсутствуют, вместо них в Unity3D есть JsonUtility. Не обязательно использовать class, можно struct.

[Serializable]
public struct TileLocation
{
    public Vector2Int position;
    public Vector2Int vector;
}

string json; // "{ "position" : { "x": 2, "y": 3 }, "vector": { "x": 1, "y": 0 } }"
TileLocation location = JsonUtility.FromJson<TileLocation>(json);

TileLocation location = new TileLocation()
{
    position = new Vector2Int(2, 3),
    vector = Vector2Int.right
};
string json = JsonUtility.ToJson(location);

Объект не обязательно должен полностью соответствовать json, это не приводит к ошибкам, излишние данные игнорируются, недостающим ничего не присваивается. То есть один json можно даже делить на несколько моделей данных.


Так-же есть различные решения в Unity Asset Store.

Yaroslav
  • 7,040
0

Если вы используете библиотеку Newtonsoft.Json, то вам подойдёт следующий класс конверта сообщения (а если вы её не используете, то пора начинать использовать):

class Message
{
    public string route;
    public JToken data; 
}

Также можно использовать в качестве конверта JObject.

После того, как вы определитесь с обработчиком, JToken можно десериализовать в конкретный тип данных:

interface IRouteHandler
{
    void Handle(JToken data);
}

abstract class RouteHandler<T> : IRouteHandler { protected abstract void Handle(T data);

void IRouteHandler.Handle(JToken data)
{
    this.Handle(data.ToObject&lt;T&gt;());
}

}

// Пример конкретного обработчика class FooHandler : RouteHandler<Foo> { protected override void Handle(T data) { // … } }

Если вам ближе не ООП, а делегаты - вот так можно "замкнуть" конкретный тип в делегате:

delegate void RouteHandler(JToken data);
delegate void RouteHandler<T>(T data);

static class Route { public RouteHandler For<T>(RouteHandler<T> handler) => data => handler(data.ToObject<T>()); }

// …

Dictionary<string, RouteHandler> routes = new { { "foo", Route.For<Foo>(() => { // … } )}, { "bar", Route.For<Bar>(() => { // … } )}, };

Наконец, если хочется чего-то совсем примитивного и без лишних сущностей, можно сами классы сообщений сделать одновременно и обработчиками:

interface IRouteHandler
{
    void Execute();
}
delegate void RouteHandler(JToken data);

static class Route { public RouteHandler For<T>() where T : IRouteHandler => data => data.ToObject<T>().Execute(); }

// …

Dictionary<string, RouteHandler> routes = new { { "foo", Route.For<Foo>() }, { "bar", Route.For<Bar>() }, };


Отмечу, что более в современной System.Text.Json вместо JToken для тех же целей нужно использовать тип JsonElement, а дальнейшая десериализация вместо ToObject делается через JsonSerializer.Deserialize<T>. В остальном всё так же.

Pavel Mayorov
  • 58,537
  • System.Text.Json недоступен в Unity. А чтобы не творить такие костыли с JToken, есть TypeNameHandling. – aepot Mar 01 '23 at 10:42
  • @aepot TypeNameHandling - это не то. Эта штука позволяет указать любой тип, а надо-то конкретный, подходящий для указанного "маршрута". – Pavel Mayorov Mar 01 '23 at 12:01