如何将对象模型保存到 JSON 并将字典序列化为其值数组


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)
};

否则,您将需要使用自定义合同解析器。

相关内容

  • 没有找到相关文章

最新更新