我在JSON中获得web服务响应,字符串如下:
{
"adjusted": true,
"queryCount": 2,
"request_id": "6a7e466379af0a71039d60cc78e72282",
"results": [
{
"c": 75.0875,
"h": 75.15,
"l": 73.7975,
"n": 1,
"o": 74.06,
"t": 1577941200000,
"v": 135647456,
"vw": 74.6099
},
{
"c": 74.3575,
"h": 75.145,
"l": 74.125,
"n": 1,
"o": 74.2875,
"t": 1578027600000,
"v": 146535512,
"vw": 74.7026
}
],
"resultsCount": 2,
"status": "OK",
"ticker": "AAPL"
}
当我使用自己的c#对象(如下)时,它们看起来是这样的,我重新序列化得很好:
public class Aggregates
{
[JsonProperty("ticker")]
public string Ticker { get; set; }
[JsonProperty("queryCount")]
public int QueryCount { get; set; }
[JsonProperty("resultsCount")]
public int ResultsCount { get; set; }
[JsonProperty("adjusted")]
public bool Adjusted { get; set; }
[JsonProperty("results")]
public List<Aggregate> Aggregatelist { get; set; }
[JsonProperty("status")]
public string Status { get; set; }
[JsonProperty("request_id")]
public string RequestId { get; set; }
[JsonProperty("count")]
public int Count { get; set; }
}
public class Aggregate
{
/// <summary>
/// The trading volume of the symbol in the given time period.
/// </summary>
[JsonProperty("v")]
public object Volume { get; set; }
/// <summary>
/// The volume weighted average price.
/// </summary>
[JsonProperty("vw")]
public double VolumeWeightedw { get; set; }
/// <summary>
/// The open price for the symbol in the given time period.
/// </summary>
[JsonProperty("o")]
public double Open { get; set; }
/// <summary>
/// The close price for the symbol in the given time period.
/// </summary>
[JsonProperty("c")]
public double Close { get; set; }
/// <summary>
/// The highest price for the symbol in the given time period.
/// </summary>
[JsonProperty("h")]
public double High { get; set; }
/// <summary>
/// The lowest price for the symbol in the given time period.
/// </summary>
[JsonProperty("l")]
public double Low { get; set; }
/// <summary>
/// The Unix Msec timestamp for the start of the aggregate window.
/// </summary>
[JsonProperty("t")]
public long StartTime { get; set; }
/// <summary>
/// The number of transactions in the aggregate window.
/// </summary>
[JsonProperty("n")]
public int TransactionsNum { get; set; }
}
然而,我现在被迫使用一个库,它有自己的c#对象Quote而不是我的Aggregate对象。我不能更改Quote对象,这是多余的。
public class Quote : IQuote
{
public Quote();
public DateTime Date { get; set; }
public decimal Open { get; set; }
public decimal High { get; set; }
public decimal Low { get; set; }
public decimal Close { get; set; }
public decimal Volume { get; set; }
}
public interface IQuote
{
DateTime Date { get; }
decimal Open { get; }
decimal High { get; }
decimal Low { get; }
decimal Close { get; }
decimal Volume { get; }
}
我可以将所有对象的数据从聚合复制到引用,但这可能是数百万个对象,我有一种直觉,可以用一种非常简洁的方式将JSON直接反序列化到引用对象,我只是找不到如何…
你可以试试这个。此代码在Visual Studio
中进行了测试。var json=... your json
List<Quote> quotes = JsonConvert
.DeserializeObject<Aggregates>(json)
.Aggregatelist.Select(a => new Quote
{
Date = UnixTimeToDateTime(a.StartTime),
Open = (decimal)a.Open,
High = (decimal)a.High,
Low = (decimal)a.Low,
Close = (decimal)a.Close,
Volume = (decimal)a.VolumeWeightedw
}).ToList();
public static DateTime UnixTimeToDateTime(long unixtime)
{
var dtDateTime = new DateTime(1970, 1, 1, 0, 0, 0, 0, DateTimeKind.Utc);
return dtDateTime.AddMilliseconds(unixtime).ToLocalTime();
}
输出[
{
"Date": "2020-01-02T01:30:00-03:30",
"Open": 74.06,
"High": 75.15,
"Low": 73.7975,
"Close": 75.0875,
"Volume": 74.6099
},
{
"Date": "2020-01-03T01:30:00-03:30",
"Open": 74.2875,
"High": 75.145,
"Low": 74.125,
"Close": 74.3575,
"Volume": 74.7026
}
]
你可以把你的类属性从双进位改为十进制
[JsonProperty("o")]
public decimal Open { get; set; }
...and so on
的代码不需要额外的强制转换,您可以替换
Open = (decimal)a.Open,
与
Open = a.Open,
... and so on
您应该能够通过扩展DefaultContractResolver
class Program
{
static void Main(string[] args)
{
var jsonStr = "{'adjusted': true,'queryCount': 2,'request_id': '6a7e466379af0a71039d60cc78e72282','results': [{"+
"'c': 75.0875,'h': 75.15,'l': 73.7975,'n': 1,'o': 74.06,'t': 1577941200000,'v': 135647456,'vw': 74.6099},"+
"{'c': 74.3575,'h': 75.145,'l': 74.125,'n': 1,'o': 74.2875,'t': 1578027600000,'v': 146535512,'vw': 74.7026}],"+
"'resultsCount': 2,'status': 'OK','ticker': 'AAPL'}";
var jsonResolver = new PropertyRenameAndIgnoreSerializerContractResolver();
jsonResolver.RenameProperty(typeof(Quote), "Close","c");
jsonResolver.RenameProperty(typeof(Quote), "Volume","vw");
jsonResolver.RenameProperty(typeof(Quote), "Open","o");
jsonResolver.RenameProperty(typeof(Quote), "Low","l");
jsonResolver.RenameProperty(typeof(Quote), "High","h");
var jsonObj = JObject.Parse(jsonStr);
var serializerSettings = new JsonSerializerSettings();
serializerSettings.ContractResolver = jsonResolver;
var objList = JsonConvert.DeserializeObject<List<Quote>>(jsonObj.SelectToken("results").ToString(), serializerSettings);
}
}
这是一个示例实现
public class PropertyRenameAndIgnoreSerializerContractResolver : DefaultContractResolver
{
private readonly Dictionary<Type, HashSet<string>> _ignores;
private readonly Dictionary<Type, Dictionary<string, string>> _renames;
public PropertyRenameAndIgnoreSerializerContractResolver()
{
_ignores = new Dictionary<Type, HashSet<string>>();
_renames = new Dictionary<Type, Dictionary<string, string>>();
}
public void IgnoreProperty(Type type, params string[] jsonPropertyNames)
{
if (!_ignores.ContainsKey(type))
_ignores[type] = new HashSet<string>();
foreach (var prop in jsonPropertyNames)
_ignores[type].Add(prop);
}
public void RenameProperty(Type type, string propertyName, string newJsonPropertyName)
{
if (!_renames.ContainsKey(type))
_renames[type] = new Dictionary<string, string>();
_renames[type][propertyName] = newJsonPropertyName;
}
protected override JsonProperty CreateProperty(MemberInfo member, MemberSerialization memberSerialization)
{
var property = base.CreateProperty(member, memberSerialization);
if (IsIgnored(property.DeclaringType, property.PropertyName))
{
property.ShouldSerialize = i => false;
property.Ignored = true;
}
if (IsRenamed(property.DeclaringType, property.PropertyName, out var newJsonPropertyName))
property.PropertyName = newJsonPropertyName;
return property;
}
private bool IsIgnored(Type type, string jsonPropertyName)
{
if (!_ignores.ContainsKey(type))
return false;
return _ignores[type].Contains(jsonPropertyName);
}
private bool IsRenamed(Type type, string jsonPropertyName, out string newJsonPropertyName)
{
Dictionary<string, string> renames;
if (!_renames.TryGetValue(type, out renames) || !renames.TryGetValue(jsonPropertyName, out newJsonPropertyName))
{
newJsonPropertyName = null;
return false;
}
return true;
}
}
和简化的Quote类
public class Quote
{
public decimal Open { get; set; }
public decimal High { get; set; }
public decimal Low { get; set; }
public decimal Close { get; set; }
public decimal Volume { get; set; }
}
您可以像这样使用自定义数据承包商:
public class QuoteDataContractResolver : DefaultContractResolver
{
public static readonly QuoteDataContractResolver Instance = new QuoteDataContractResolver();
protected override JsonProperty CreateProperty(MemberInfo member, MemberSerialization memberSerialization)
{
var property = base.CreateProperty(member, memberSerialization);
if (property.DeclaringType == typeof(Quote))
{
switch (property.PropertyName)
{
case "Date":
property.PropertyName = "d";
break;
case "Open":
property.PropertyName = "o";
break;
//and so on for all the other props
}
}
return property;
}
}
并像这样使用:
Quote q = new Quote { };
var settings = new JsonSerializerSettings
{
ContractResolver = QuoteDataContractResolver.Instance
};
//Serialize
var jsonStr = JsonConvert.SerializeObject(q, settings);
//Deserialize
q = JsonConvert.DeserializeObject<Quote>(jsonStr, settings);
编辑:对象最终应该是这样的:
public class QuoteWrapper
{
public bool adjusted;
public int queryCount;
public string request_id;
public Quote[] results;
public int resultsCount;
public string status;
public string ticker;
}
这是你在问题中提供的json字符串接收到的对象
示例如下:https://dotnetfiddle.net/KsIXeV