public class Portfolio
{
public string Name {get; set;}
public Dictionary<string,Position> Positions {get; set;}
}
public class Position
{
public string Ticker {get; set;}
public decimal Size {get; set;}
}
JsonConvert.SerializeObject(portfolio);
将产生例如:
{
"Name": "SP500",
"Positions": {
"AOS": {
"Ticker": "AOS",
"Size": 100,
},
"ABT": {
"Ticker": "ABT",
"Size": 100,
}
}
}
但是我想最小化空间并将位置存储为数组:
{
"Name": "SP500",
"Positions":
[
{
"Ticker": "AOS",
"Size": 100,
},
{
"Ticker": "ABT",
"Size": 100,
}
]
}
如何将此 json 保存并加载到我的对象模型中?
使用这个:
public class Portfolio
{
public string Name {get; set;}
public List<Position> Positions {get; set;}
}
您可以为Dictionary<string,Position>
添加自定义JsonConverter
,将字典值序列化为列表。转换器假定在反序列化期间可以以某种方式从字典值中提取字典键。
首先,定义以下转换器:
public class PositionDictionaryConverter : DictionaryAsValueListConverter<Position>
{
protected override string GetKey(Position position) { return position.Ticker; }
}
public abstract class DictionaryAsValueListConverter<TValue> : JsonConverter
{
protected abstract string GetKey(TValue value);
public override bool CanConvert(Type objectType)
{
return typeof(Dictionary<string, TValue>).IsAssignableFrom(objectType);
}
public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
{
if (reader.MoveToContent().TokenType == JsonToken.Null)
return null;
var list = serializer.Deserialize<List<TValue>>(reader);
var dictionary = (IDictionary<string, TValue>)(existingValue ?? serializer.ContractResolver.ResolveContract(objectType).DefaultCreator());
foreach (var item in list)
dictionary.Add(GetKey(item), item);
return dictionary;
}
public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
{
serializer.Serialize(writer, ((IDictionary<string, TValue>)value).Values);
}
}
public static partial class JsonExtensions
{
public static JsonReader MoveToContent(this JsonReader reader)
{
if (reader.TokenType == JsonToken.None)
reader.Read();
while (reader.TokenType == JsonToken.Comment && reader.Read())
;
return reader;
}
}
然后将其应用于模型,如下所示:
public class Portfolio
{
public string Name {get; set;}
[JsonConverter(typeof(PositionDictionaryConverter))]
public Dictionary<string,Position> Positions {get; set;}
}
或者,在设置中使用它,如下所示:
var settings = new JsonSerializerSettings
{
Converters = { new PositionDictionaryConverter() },
};
var json = JsonConvert.SerializeObject(root, settings);
当然,转换器假设字典键和股票代码相同。
演示小提琴在这里。
您可以将模型更改为:
public class Portfolio
{
public string Name {get; set;}
public List<Position> Positions {get; set;}
}
将投资组合的对象模型更改为以下内容有什么问题吗? 我认为这会序列化您想要的方式。 您可能必须使用 LINQ 在列表中查找所需的对象。 这也是假设总会有唯一的股票代码
public class Portfolio
{
public string Name {get; set;}
public List<Position> Positions {get; set;}
}
最简单的选择是编写一个用于序列化目的的单独模型:
类:
public class Portfolio
{
public string Name { get; set; }
public Dictionary<string, Position> Positions { get; set; }
}
//this is a class used just for serialization
public class PortfolioForSerialization
{
public string Name { get; set; }
public Position[] Positions { get; set; }
}
public class Position
{
public string Ticker { get; set; }
public decimal Size { get; set; }
}
用法:
//The portfolio class you want to work with (dictionary property)
var portfolio = new Portfolio()
{
Name = "MyPortfolio",
Positions = new Dictionary<string, UserQuery.Position>()
{
{ "AOS", new Position() { Size = 10, Ticker = "AOS"}},
{ "ABT", new Position() { Size = 100, Ticker = "ABT"}}
}
};
//Only used for serialization
var forSerialization = new PortfolioForSerialization()
{
Name = portfolio.Name,
Positions = portfolio.Positions.Select(p => p.Value).ToArray()
};
string serialized = JsonConvert.SerializeObject(forSerialization);
//On deserialization, map the array back to a dictionary
var deserializedPortfolio = JsonConvert.DeserializeObject<PortfolioForSerialization>(serialized);
//Map the serialization model back to your working model
var workingPortfolio = new Portfolio()
{
Name = deserializedPortfolio.Name,
Positions = deserializedPortfolio.Positions.ToDictionary(k => k.Ticker, v => v)
};
否则,您将需要使用自定义合同解析器。