我希望Json.NET反序列化器能够直接使用:ArrayWrapper[] Array { get; set; }
属性。
我应该编写自定义JsonConverter
还是更简单的方法?
public class Obj {
//public ArrayWrapper[] Array { get; set; } // I want it to work!!!
[JsonProperty( "array" )]
public int[][] Array_ { get; set; }
[JsonIgnore]
public ArrayWrapper[] Array => Array_.Select( i => new ArrayWrapper( i ) ).ToArray();
}
public struct ArrayWrapper {
private readonly int[] array;
public int Item0 => array[ 0 ];
public int Item1 => array[ 1 ];
public ArrayWrapper(int[] array) {
this.array = array;
}
public static implicit operator ArrayWrapper(int[] array) {
return new ArrayWrapper( array );
}
}
注意:数组数组由以下API返回:https://github.com/binance-exchange/binance-official-api-docs/blob/master/rest-api.md#klinecandlestick-data。我想将内部数组转换为对象。
答案 0 :(得分:2)
如果您只是想在代理包装器对象中捕获集合,那么最简单的方法是使包装器看起来像是Json.NET的只读集合。为此,您必须:
IEnumerable<T>
(此处为T
)实施int
。IEnumerable<T>
添加一个采用T
的构造函数。 (根据实验,采用T []
的构造函数是不够的。)因此,如果您按以下方式定义ArrayWrapper
:
public struct ArrayWrapper : IEnumerable<int>
{
private readonly int[] array;
public int Item0 { get { return array[ 0 ]; } }
public int Item1 { get { return array[ 1 ]; } }
public ArrayWrapper(int[] array) {
this.array = array;
}
public ArrayWrapper(IEnumerable<int> enumerable)
{
this.array = enumerable.ToArray();
}
public static implicit operator ArrayWrapper(int[] array) {
return new ArrayWrapper( array );
}
public IEnumerator<int> GetEnumerator()
{
return (array ?? Enumerable.Empty<int>()).GetEnumerator();
}
#region IEnumerable Members
IEnumerator IEnumerable.GetEnumerator()
{
return GetEnumerator();
}
#endregion
}
您将能够将Obj
序列化和反序列化为以下JSON:
{"Array":[[1,101]]}
演示小提琴#1 here。
但是,在注释中您提到数组实际上具有固定的架构,如 Public Rest API for Binance: Kline/Candlestick data 中所述。如果是这样,您可以采用从this answer到 C#: Parsing a non-JSON array-only api response to a class object with x properties 的方法,该方法专门处理Binance Kline /烛台数据:
[JsonProperty(Order = N)]
标记每个属性以指示相对数组位置。 (可以使用[DataContract]
和[DataMember(Order = N)]
。)ObjectToArrayConverter<ArrayWrapper>()
。即对于问题中显示的特定模型,请如下修改其定义:
[JsonConverter(typeof(ObjectToArrayConverter<ArrayWrapper>))]
public struct ArrayWrapper
{
[JsonProperty(Order = 1)]
public int Item0 { get; set; }
[JsonProperty(Order = 2)]
public int Item1 { get; set; }
}
您将能够(反)序列化相同的JSON。请注意,该转换器是完全通用的,并且可以在出现将具有固定模式的数组反序列化为对象的模式时重新使用。
(由于可变结构为discouraged,因此您可能还希望将struct
更改为class
。)
答案 1 :(得分:0)
我制作了 results = [pool.apply_async(foo, (i,)) for i in range(4)]
# `pool.apply_async()` immediately returns AsyncResult (ApplyResult) object
for res in results:
res.get()
版。
我的error_callback
只是将ArrayToObjectConverter
转换为具有属性:Item1,Item2,Item3 ...的ArrayToObjectConverter
,然后反序列化此对象。
JArray
您应将JObject
用于这样的对象:
public class ArrayToObjectConverter : JsonConverter {
public override bool CanRead => true;
public override bool CanWrite => true;
public override bool CanConvert(Type type) {
return false;
}
public override object ReadJson(JsonReader reader, Type type, object existingInstance, JsonSerializer serializer) {
var contract = (JsonObjectContract) serializer.ContractResolver.ResolveContract( type );
var instance = existingInstance ?? contract.DefaultCreator();
var array = JArray.Load( reader );
var obj = Convert( array );
serializer.Populate( obj.CreateReader(), instance );
return instance;
}
public override void WriteJson(JsonWriter writer, object instance, JsonSerializer serializer) {
var contract = (JsonObjectContract) serializer.ContractResolver.ResolveContract( instance.GetType() );
var properties = contract.Properties.Where( IsSerializable );
var values = properties.Select( i => i.ValueProvider.GetValue( instance ) );
serializer.Serialize( writer, values );
}
// Helpers
private static JObject Convert(JArray array) {
var obj = new JObject();
for (var i = 0; i < array.Count; i++) {
obj.Add( "Item" + i, array[ i ] );
}
return obj;
}
private static bool IsSerializable(JsonProperty property) {
return !property.Ignored && property.Readable && property.Writable;
}
}
只有我不确定ArrayToObjectConverter
是否总是正确的顺序。