2015-05-22 130 views
2

我有一個用作字典鍵的c#結構體。爲了使該字典轉換爲JSON我需要結構序列化爲字符串(就像json.net的內置結構)。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); 

的最後一條語句,因爲它不叫了我的解析方法或公共構造失敗。 我跟着文檔,但不能通過這個。

+1

您應該不能正常使用'struct' ......除非你有特別的問題,你應該使用'class'。當你可以使用'Length'時儘量不要使用'Count()' – xanatos

+1

結構總是有一個公共無參數的構造函數,這就是爲什麼Json.Net能夠完全反序列化結構的原因。你爲什麼期望解串器能夠調用你的方法,爲什麼你需要它們? 'Level'屬性應該已經被序列化了 –

+0

請參見http://stackoverflow.com/a/7010231/613130 Json.NET和Dictionary鍵有侷限性 – xanatos

回答

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

總之我創建轉換器的字典(而不是結構),這是給我的悲痛和父類的屬性。這使得json.net在反序列化時調用我的自定義邏輯。 已經有內置的進庫這是令詞典序列化呼叫到結構的ToString創建字典的鍵(這使得它稍微不一致的,因爲它不尊重回路,即使文件排序表明,它 - http://docs.servicestack.net/text-serializers/json-serializer)時

一痛苦的一點是,我需要爲每個不同類型的字典提供單獨的轉換器,這些字典使用結構作爲其關鍵字,例如

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

將需要另一個轉換器。 我需要看看泛型是否可以用來增加重用,但如果我可以爲結構提供單個轉換器,那麼將會更好,因爲它可以用於我擁有的所有不同的字典屬性。

無論如何,我希望這有助於節省時間。

感謝所有誰提出的建議,大大appriciated