2016-05-12 51 views
5

我遇到了使用json.net序列化數據的奇怪問題。主要是,我試圖將傳出的json中的'Key'和'Value'名稱重新命名爲更具描述性的名稱。具體來說,我希望將與IRequest相關的'Key'稱爲'Request',將IQuoteTimeSeries'Value''DataSeries'當使用JSON.NET序列化複雜詞典時更改'Key'和'Value'的名稱

注意,這不會被反序列化。它僅用於網頁上的數據分析。

我正在序列化的數據存儲庫對象是一個Dictionary<IRequest, IQuoteTimeSeries>對象。 IRequest代表對數據的特定請求,IQuoteTimeSeries是包含返回數據的對象,如SortedDictionary<DateTime, IQuote>。這是按時間戳排序的一系列數據。在這個例子中,爲了簡潔,我只在TimeSeries中有一個項目,但是在大多數情況下會有很多項目。

一切都需要組織在一起,序列化併發送出去供JavaScript使用。

這是這些對象的基本代碼;

[JsonArray] 
public class QuoteRepository : Dictionary<IRequest, IQuoteTimeSeries>, IQuoteRepository 
{ 
    public QuoteRepository() { } 

    public void AddRequest(IRequest request) 
    { 
     if (!this.ContainsKey(request)) 
     { 
      IQuoteTimeSeries tSeries = new QuoteTimeSeries(request); 
      this.Add(request, tSeries); 
     } 
    } 

    public void AddQuote(IRequest request, IQuote quote) 
    {   
     if (!this.ContainsKey(request)) 
     { 
      QuoteTimeSeries tSeries = new QuoteTimeSeries(request); 
      this.Add(request, tSeries); 
     }   
     this[request].AddQuote(quote);   
    }  

    IEnumerator<IQuoteTimeSeries> Enumerable<IQuoteTimeSeries>.GetEnumerator() 
    { 
     return this.Values.GetEnumerator(); 
    } 
} 

報價時間系列看起來像這樣;

[JsonArray] 
public class QuoteTimeSeries: SortedDictionary<DateTime, IQuote>, IQuoteTimeSeries 
{ 
    public QuoteTimeSeries(IRequest request) 
    { 
     Request = request; 
    } 
    public IRequest Request { get; } 
    public void AddQuote(IQuote quote) 
    { 
     this[quote.QuoteTimeStamp] = quote; 
    } 

    public void MergeQuotes(IQuoteTimeSeries quotes) 
    { 
     foreach (IQuote item in quotes) 
     { 
      this[item.QuoteTimeStamp] = item; 
     } 
    } 

    IEnumerator<IQuote> IEnumerable<IQuote>.GetEnumerator() 
    { 
     return this.Values.GetEnumerator(); 
    } 

} 

用於序列化此代碼是相當簡單:

IQuoteRepository quotes = await requests.GetDataAsync(); 

JsonSerializerSettings settings = new JsonSerializerSettings 
{ 
    ContractResolver = QuoteRepositoryContractResolver.Instance, 
    NullValueHandling = NullValueHandling.Ignore 
}; 

return Json<IQuoteRepository>(quotes, settings); 

我加了一個合同與解析器重寫財產寫作的意圖。正在命中property.PropertyName =代碼並且屬性名稱正在更改,但輸出JSON不受影響。

public class QuoteRepositoryContractResolver : DefaultContractResolver 
{ 
    public static readonly QuoteRepositoryContractResolver Instance = new QuoteRepositoryContractResolver(); 

    protected override JsonProperty CreateProperty(MemberInfo member, MemberSerialization memberSerialization) 
    { 
     JsonProperty property = base.CreateProperty(member, memberSerialization); 

     if (property.DeclaringType == typeof(KeyValuePair<IRequest, IQuoteTimeSeries>)) 
     { 
      if (property.PropertyName.Equals("Key", StringComparison.OrdinalIgnoreCase)) 
      { 
       property.PropertyName = "Request"; 
      } 
      else if (property.PropertyName.Equals("Value", StringComparison.OrdinalIgnoreCase)) 
      { 
       property.PropertyName = "Data"; 
      } 
     } 
     else if (property.DeclaringType == typeof(KeyValuePair<DateTime, IQuote>)) 
     { 
      if (property.PropertyName.Equals("Key", StringComparison.OrdinalIgnoreCase)) 
      { 
       property.PropertyName = "TimeStamp"; 
      } 
      else if (property.PropertyName.Equals("Value", StringComparison.OrdinalIgnoreCase)) 
      { 
       property.PropertyName = "Quote"; 
      } 
     } 
     return property; 
    } 
} 

輸出JSON是奇數。儘管我確實在代碼中更改了名稱,但Key和Value項目完全不變。

[ 
    { 
     "Key": { 
      "QuoteDate": "2016-05-12T00:00:00-04:00", 
      "QuoteType": "Index", 
      "Symbol": "SPY", 
      "UseCache": true 
     }, 
     "Value": [ 
      { 
       "Key": "2016-05-11T16:00:01-04:00", 
       "Value": { 
        "Description": "SPDR S&amp;P 500", 
        "High": 208.54, 
        "Low": 206.50, 
        "Change": -1.95, 
        "ChangePer": -0.94, 
        "Price": 206.50, 
        "QuoteTimeStamp": "2016-05-11T16:00:01-04:00", 
        "Symbol": "SPY" 
       } 
      } 
     ] 
    }, 
    { 
     "Key": { 
      "QuoteDate": "2016-05-12T00:00:00-04:00", 
      "QuoteType": "Stock", 
      "Symbol": "GOOG", 
      "UseCache": true 
     }, 
     "Value": [ 
      { 
       "Key": "2016-05-11T16:00:00-04:00", 
       "Value": { 
        "Description": "Alphabet Inc.", 
        "High": 724.48, 
        "Low": 712.80, 
        "Change": -7.89, 
        "ChangePer": -1.09, 
        "Price": 715.29, 
        "QuoteTimeStamp": "2016-05-11T16:00:00-04:00", 
        "Symbol": "GOOG" 
       } 
      } 
     ] 
    } 
] 

有誰知道如何正確地更改'鑰匙'和'價值'項目?

+0

@Brian Rogers謝謝你的清理。我的打字技巧在凌晨4:00並不總是那麼棒。 :-) – drobertson

+0

不用擔心,男人。 –

回答

4

解決此問題的一種方法是對基於字典的類使用自定義JsonConverter。代碼實際上非常簡單。

public class CustomDictionaryConverter<K, V> : JsonConverter 
{ 
    private string KeyPropertyName { get; set; } 
    private string ValuePropertyName { get; set; } 

    public CustomDictionaryConverter(string keyPropertyName, string valuePropertyName) 
    { 
     KeyPropertyName = keyPropertyName; 
     ValuePropertyName = valuePropertyName; 
    } 

    public override bool CanConvert(Type objectType) 
    { 
     return typeof(IDictionary<K, V>).IsAssignableFrom(objectType); 
    } 

    public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer) 
    { 
     IDictionary<K, V> dict = (IDictionary<K, V>)value; 
     JArray array = new JArray(); 
     foreach (var kvp in dict) 
     { 
      JObject obj = new JObject(); 
      obj.Add(KeyPropertyName, JToken.FromObject(kvp.Key, serializer)); 
      obj.Add(ValuePropertyName, JToken.FromObject(kvp.Value, serializer)); 
      array.Add(obj); 
     } 
     array.WriteTo(writer); 
    } 

    public override bool CanRead 
    { 
     get { return false; } 
    } 

    public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer) 
    { 
     throw new NotImplementedException(); 
    } 
} 

當它是時間序列化,轉換器添加到JsonSerializerSettings這樣的:

JsonSerializerSettings settings = new JsonSerializerSettings 
{ 
    Converters = new List<JsonConverter> 
    { 
     new CustomDictionaryConverter<IRequest, IQuoteTimeSeries>("Request", "Data"), 
     new CustomDictionaryConverter<DateTime, IQuote>("TimeStamp", "Quote") 
    }, 
    Formatting = Formatting.Indented 
}; 

string json = JsonConvert.SerializeObject(repo, settings); 

小提琴:https://dotnetfiddle.net/roHEtx

+0

謝謝。我跑了一些測試,上面的代碼完全像我需要的那樣工作。我一直在試圖找出如何修改這些價值觀的牆壁上。你的回答很完美。 – drobertson

+0

很高興我能幫到你。 –

0

Dictionary<IRequest, IQuoteTimeSeries>List<KeyValuePair<IRequest, IQuoteTimeSeries>>轉換你的字典也應該工作。

相關問題