【问题标题】:Change Name of 'Key' and 'Value' when using JSON.NET to serialize complex Dictionary使用 JSON.NET 序列化复杂字典时更改“键”和“值”的名称
【发布时间】:2016-05-12 08:57:15
【问题描述】:

我在使用 json.net 序列化数据时遇到了一个奇怪的问题。主要是,我试图将传出 json 中的“键”和“值”名称重命名为更具描述性的名称。具体来说,我希望将 IRequest 相关的“Key”称为“Request”,将 IQuoteTimeSeries 的“Value”称为“DataSeries”

注意,这不会被反序列化。只用于网页的数据分析。

我正在序列化的数据存储库对象是一个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"
                }
            }
        ]
    }
]

有人知道如何正确更改“Key”和“Value”项目吗?

【问题讨论】:

  • @Brian Rogers 感谢您的清理。早上 4:00 我的打字技巧并不总是那么好。 :-)

标签: c# json serialization json.net


【解决方案1】:

解决此问题的一种方法是为基于字典的类使用自定义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

【讨论】:

  • 谢谢。我进行了一些测试,上面的代码完全符合我的需要。我一直在拼命想弄清楚如何修改这些值。你的回答很完美。
  • 很高兴我能帮上忙。
【解决方案2】:

将您的字典从Dictionary&lt;IRequest, IQuoteTimeSeries&gt; 转换为List&lt;KeyValuePair&lt;IRequest, IQuoteTimeSeries&gt;&gt; 也应该可以。

【讨论】:

    猜你喜欢
    • 2014-08-21
    • 1970-01-01
    • 1970-01-01
    • 2012-02-06
    • 1970-01-01
    • 2019-12-10
    • 2021-11-01
    相关资源
    最近更新 更多