JSON.Net 到 serialize/deserialize 结构到字符串

JSON.Net to serialize/deserialize struct to string

我有一个用作字典键的 C# 结构。为了使该字典转换为 json 我需要将结构序列化为字符串(就像 json.net 对内置结构所做的那样)。

public struct CreditRating
{
    public CreditRating(string json) : this()
    {
        var levels = json.Split(new[] { '~' }, StringSplitOptions.None);
        if (levels.Count() >= 3) Level3 = levels[2];
        if (levels.Count() >= 2) Level2 = levels[1];
        if (levels.Any()) Level1 = levels[0];
    }

    public string Level1 { get; set; }
    public string Level2 { get; set; }
    public string Level3 { get; set; }

    public override string ToString()
    {
        return string.Format("{0}~{1}~{2}", Level1, Level2, Level3);
    }

    public static CreditRating Parse(string json)
    {
        return new CreditRating(json);
    }
}

还有我的测试:

        var rating = new CreditRating { Level1 = "first", Level2 = "Sergey" };
        var ratingJson = JsonConvert.SerializeObject(rating); // {"Level1":"first","Level2":"Sergey","Level3":null}
        var rating2 = JsonConvert.DeserializeObject<CreditRating>(ratingJson);

        var dict = new Dictionary<CreditRating, double> {{rating, 2d}};
        var dictJson = JsonConvert.SerializeObject(dict); //{"first~Sergey~":2.0}
        var failingTest = JsonConvert.DeserializeObject<Dictionary<CreditRating, double>>(dictJson);

最后一条语句失败,因为它没有调用我的 Parse 方法或 public 构造函数。 我按照文档进行操作,但无法通过此操作。

好的,所以在尝试了很多事情之后这最终奏效了——以防其他人遇到这个:

[DataContract(Namespace = ContractNamespace.Current)]
public class CreditSpreadShiftWithLevels
{
    [OnDeserializing]
    private void Initialize(StreamingContext ctx)
    {
        ShiftsByRating = new Dictionary<CreditRating, double>();
    }
    [DataMember]
    public bool SplitByRating { get; set; }

    [DataMember]
    public double ShiftValue { get; set; }

    [DataMember]
    [JsonConverter(typeof(CreditRatingDoubleDictionaryConverter))]
    public Dictionary<CreditRating, double> ShiftsByRating { get; set; }

    //other properties

}

[DataContract(Namespace = ContractNamespace.Current)]
public struct CreditRating
{
    public CreditRating(string json): this()
    {
        var levels = json.Split(new[] { '~' }, StringSplitOptions.None);
        var cnt = levels.Length;
        if (cnt >= 3) Level3 = levels[2];
        if (cnt >= 2) Level2 = levels[1];
        if (cnt >= 1) Level1 = levels[0];
    }

    [DataMember]
    public string Level1 { get; set; }
    [DataMember]
    public string Level2 { get; set; }
    [DataMember]
    public string Level3 { get; set; }

    public override string ToString()
    {
        return string.Format("{0}~{1}~{2}", Level1, Level2, Level3);
    }
}


public class CreditRatingDoubleDictionaryConverter : JsonConverter
{
    public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
    {
        serializer.Serialize(writer, value);
    }

    public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
    {
        var dict = new Dictionary<CreditRating, double>();
        while (reader.Read())
        {
            if (reader.TokenType == JsonToken.PropertyName)
            {
                string readerValue = reader.Value.ToString();
                var cr = new CreditRating(readerValue);
                if (reader.Read() && reader.TokenType == JsonToken.Float)
                {
                    var val = Convert.ToDouble(reader.Value);
                    dict.Add(cr, val);
                }
            }
            if (reader.TokenType == JsonToken.EndObject) return dict;
        }
        return dict;
    }

    public override bool CanConvert(Type objectType)
    {
        return typeof(Dictionary<CreditRating, double>).IsAssignableFrom(objectType);
    }
}

简而言之,我为字典(而不是结构)创建了转换器,这让我感到悲伤并归因于父 class 的 属性。这使得 json.net 在反序列化时调用我的自定义逻辑。 库中已经内置了一些东西,可以在创建字典键时将字典序列化调用到结构的 ToString 中(这使得它稍微不一致,因为它不遵守 return 路由,即使文档有点建议 - http://docs.servicestack.net/text-serializers/json-serializer)

一个痛点是我需要为每种使用结构作为其键的不同类型的字典提供单独的转换器,例如

public Dictionary<CreditRating, List<string>> BucketsByRating { get; set; }

需要另一个转换器。 我需要看看是否可以使用泛型来增加重用,但如果我可以为结构提供单个转换器,以便为我拥有的所有不同字典属性选择,那就更好了。

无论如何,我希望这会有所帮助并节省一些时间。

感谢所有提供建议的人,非常感谢