CSharp · Console
using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Runtime.Serialization.Formatters;
using System.IO;
using System.Data;
using System.ComponentModel.DataAnnotations;
using System.Globalization;
using System.Reflection;
using System.Collections.ObjectModel;
using System.Diagnostics;
using System.Runtime.Serialization;
using System.Text.Json;
using System.Text.Json.Serialization;
#nullable enable
using NUnit.Framework; // Throws NUnit.Framework.AssertionException
//https://stackoverflow.com/questions/72260232/deserializing-array-of-price-quantity
// Converter Copied verbatim from this answer https://stackoverflow.com/a/71649515/3744182
// By https://stackoverflow.com/users/15283686/yueyinqiu
// To https://stackoverflow.com/questions/71649101/system-text-json-fails-to-deserialize-listlistobject
[AttributeUsage(AttributeTargets.Property, Inherited = true, AllowMultiple = false)]
public sealed class JsonPlainArrayIndexAttribute : Attribute
{
readonly int index;
public JsonPlainArrayIndexAttribute(int index)
{
this.index = index;
}
public int Index
{
get { return index; }
}
}
public sealed class JsonPlainArrayConverter<T> : JsonConverter<T> where T : new()
{
public override T? Read(
ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)
{
Debug.Assert(typeof(T) == typeToConvert);
var props = typeToConvert.GetProperties();
var linq = from prop in props
let attr = prop.GetCustomAttributes(typeof(JsonPlainArrayIndexAttribute), true)
where prop.CanWrite && attr.Length is 1
orderby ((JsonPlainArrayIndexAttribute)attr[0]).Index
select prop;
var arr = JsonSerializer.Deserialize<IEnumerable<JsonElement>>(ref reader, options);
if (arr is null)
return default;
var result = new T();
foreach (var (prop, value) in linq.Zip(arr))
prop.SetValue(result, value.Deserialize(prop.PropertyType, options));
return result;
}
public override void Write(Utf8JsonWriter writer, T value, JsonSerializerOptions options)
{
var type = typeof(T);
var props = type.GetProperties();
var linq = from prop in props
let attr = prop.GetCustomAttributes(typeof(JsonPlainArrayIndexAttribute), true)
where prop.CanRead && attr.Length is 1
orderby ((JsonPlainArrayIndexAttribute)attr[0]).Index
select prop.GetValue(value);
JsonSerializer.Serialize<IEnumerable<object>>(writer, linq, options);
}
}
///
[JsonNumberHandling(JsonNumberHandling.AllowReadingFromString)]
public record Depth(
//[property: JsonPropertyName("type")] DepthType Type,
[property: JsonPropertyName("pair")] string Pair,
[property: JsonPropertyName("sequence")] long Sequence,
[property: JsonPropertyName("asks")] List<BookLevel> Asks,
[property: JsonPropertyName("bids")] List<BookLevel> Bids,
[property: JsonPropertyName("prev_sequence")] long PreviousSequence
//[property: JsonPropertyName("changes")] IEnumerable<Changes> Changes
);
//Compilation error:
//[JsonConverter(typeof(JsonStringEnumMemberConverter))]
public enum DepthType
{
[EnumMember(Value = "snapshot")]
Snapshot,
[EnumMember(Value = "update")]
Update
}
[JsonConverter(typeof(JsonPlainArrayConverter<BookLevel>))]
//ERROR:
[JsonNumberHandling(JsonNumberHandling.AllowReadingFromString)]
public record BookLevel
{
[JsonPlainArrayIndex(0)]
public string Price { get; init; }
[JsonPlainArrayIndex(1)]
public string Quantity { get; init; }
}
public record Changes(string Side, decimal Price, decimal Quantity);
class TestClass
{
public static void Test()
{
var json = GetJson();
var options = new JsonSerializerOptions
{
PropertyNameCaseInsensitive = true,
NumberHandling = JsonNumberHandling.AllowReadingFromString,
};
var model = JsonSerializer.Deserialize<Depth>(json, options);
model.Dump();
}
static string GetJson() => @"{
""type"":""snapshot"",
""pair"":""BTC-USDT"",
""sequence"":9,
""bids"":[
[
""0.08000000"",
""0.10000000""
]
],
""asks"":[
[
""0.09000000"",
""0.20000000""
]
]
}
";
}
public class Program
{
public static void Main()
{
Console.WriteLine("Environment version: {0} ({1}), {2}", System.Runtime.InteropServices.RuntimeInformation.FrameworkDescription , Environment.Version, Environment.OSVersion);
Console.WriteLine("System.Text.Json version: " + typeof(JsonSerializer).Assembly.FullName);
Console.WriteLine();
try
{
TestClass.Test();
}
catch (Exception ex)
{
Console.WriteLine("Failed with unhandled exception: ");
Console.WriteLine(ex);
throw;
}
}
}