Прямой json к байту сериализации StructureMap [] - PullRequest
2 голосов
/ 26 апреля 2020

У меня есть следующее JSON (получено как байт [] из веб-сокета):

{
    "ev": "T",              // Event Type
    "sym": "MSFT",          // Symbol Ticker
    "x": 4,                 // Exchange ID
    "i": "12345",           // Trade ID
    "z": 3,                 // Tape ( 1=A 2=B 3=C)
    "p": 114.125,           // Price
    "s": 100,               // Trade Size
    "c": [0, 1],           // Trade Conditions
    "t": 1536036818784      // Trade Timestamp ( Unix MS )
}

И структура:

struct Trade
{
    [JsonPropertyName("sym")]
    public string  Symbol { get; set; }
    [JsonPropertyName("p")]
    public decimal Price { get; set; }
    ...
}

В настоящее время я иду от JSON в структуру (используя удивительную Utf8Json lib), затем из структуры в bytes[].

I * sh до go прямо из JSON в MessagePack сериализованный байтовый объект - поскольку средний шаг кажется немного избыточным.

Как можно добиться этого, сохраняя сопоставления свойств выше?

В идеале, поскольку я получаю JSON в виде байта [], я хотел бы напрямую использовать байты (вместо кодирования в строку - или, если это необходимо сделать, по крайней мере, в кодировке, не требующей больших накладных расходов).

Я могу использовать атрибуты (для JSON mapping), если это сделает все проще!

В настоящее время я смотрю на MessagePackWriter в необработанный буфер (отрабатывая управление памятью, если мне нужно будет использовать MemoryManager или просто сделать свой собственный * 1022). * arrays et c).

Идея будет состоять в том, чтобы записать поток непосредственно во время декодирования, и полностью исключить структуру Trade:

private void GetTrade(ref Utf8JsonReader reader, IBufferWriter<byte> bufferWriter)
{
    var trade = new Trade
    {
        TradeConditions = new int[] { }
    };

    // working how to use writer out :)
    var writer = new MessagePackWriter(bufferWriter);

    while (Expect(ref reader, JsonTokenType.PropertyName, JsonTokenType.EndObject))
    {
        var property = reader.GetString();

        switch (property)
        {
            default:
                this.logger.LogError($"decoding {trade.GetType().Name} found unexpected property {property}, skipping");
                reader.Skip();
                break;
            case StreamFieldNames.Symbol:
                trade.Symbol = ExpectString(ref reader, StreamFieldNames.Symbol);
                break;
            case StreamFieldNames.ExchangeId:
                trade.ExchangeId = ExpectInt(ref reader, StreamFieldNames.ExchangeId);
                break;
            case StreamFieldNames.TradeId:
                trade.TradeId = ExpectString(ref reader, StreamFieldNames.TradeId);
                break;
            case StreamFieldNames.Tape:
                trade.Tape = ExpectInt(ref reader, StreamFieldNames.Tape);
                break;
            case StreamFieldNames.Price:
                trade.Price = ExpectDecimal(ref reader, StreamFieldNames.Price);
                break;
            case StreamFieldNames.TradeSize:
                trade.TradeSize = ExpectDecimal(ref reader, StreamFieldNames.TradeSize);
                break;
            case StreamFieldNames.TradeConditions:
                trade.TradeConditions = ExpectIntArray(ref reader, StreamFieldNames.TradeConditions);
                break;
            case StreamFieldNames.Timestamp:
                trade.Timestamp = ExpectUnixTimeMilliseconds(ref reader, StreamFieldNames.Timestamp);
                break;
        }
    }
    return trade;
}

1 Ответ

0 голосов
/ 05 мая 2020

Если я правильно понимаю, вы получаете байт [] и хотите получить структуру Trade без преобразования байта [] в строку? В этом случае вы можете использовать библиотеку Marshal для приведения неуправляемого объекта в управляемый:

    public T ByteArrayToStructure<T>(byte[] bytes) where T : struct
    {
        T result;
        GCHandle handle = GCHandle.Alloc(bytes, GCHandleType.Pinned);
        try
        {
            result = (T)Marshal.PtrToStructure(handle.AddrOfPinnedObject(), typeof(T));
        }
        finally
        {
            handle.Free();
        }
        return result;
    }

. Для этого вам нужно будет включить System.Runtime.InteropServices. И в этом случае byte [] должен будет содержать все поля в структуре, как объявлено, поэтому вам не нужно будет иметь никаких атрибутов. Вы можете получить больше объяснений и примеров на сайте codeproject , как это работает. Хотя эта проблема легко может быть решена в C или C ++, здесь, в C#, у нас нет указателей, которые облегчают нам жизнь, но также удаляют некоторые функциональные возможности.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...