JSON.Net将struct序列化/反序列化为字符串

时间:2015-05-22 10:12:08

标签: c# json struct json.net

我有一个用作字典键的c#结构。为了使该字典转换为json,我需要将struct序列化为字符串(就像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方法或公共构造函数。 我按照文档进行了操作但无法通过此文件。

1 个答案:

答案 0 :(得分:2)

好的,所以在尝试了很多事情之后,这最终有效 - 如果其他人碰到这个:

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

简而言之,我为字典(而不是struct)创建了转换器,它给了我悲伤和父类的属性。这使得json.net在反序列化时调用我的自定义逻辑。 库中已经存在一些内容,它使字典序列化在创建字典键时调用struct的ToString(这使得它稍微不一致,因为它不尊重返回路由,即使文档类型暗示它 - {{3} })

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

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

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

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

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