【问题标题】:How to make Json Serialize ignore dictionary keys如何使 Json 序列化忽略字典键
【发布时间】:2020-02-18 11:11:57
【问题描述】:

我正在尝试序列化一个类中的字典,即使我将 ProcessDictionaryKeys 参数设置为 false,CustomAttributes 字典中的键也会被格式化。

我已经添加了[JsonProperty],如下图:

[JsonProperty(NamingStrategyType = typeof(SnakeCaseNamingStrategy), NamingStrategyParameters = new object[] { false, false })]
public IDictionary<string, string> CustomAttributes { get; set; }

我的 CustomAttributes 数据如下所示:

CustomAttributes = new Dictionary<string, string>()
{
    {"Custom Attribute 1", "1"},
    {"CustomAttribute 2", "2"}
}

生成的 JSON 如下所示:

custom_attributes\":{\"custom Attribute 1\":\"1\",\"customAttribute 2\":\"2\"

如您所见,每个字典键的第一个字母都没有大写。我怎样才能阻止这种情况发生?

编辑:将 ProcessDictionaryKeys 参数更改为 true 似乎没有任何区别。

【问题讨论】:

  • 删除这个NamingStrategyType = typeof(SnakeCaseNamingStrategy) ?
  • 所有这一切就是将字典的名称更改为默认的驼峰式:customAttributes\":{\"custom Attribute 1\":\"1\",\"customAttribute 2\":\"2
  • 是的,但这是你的问题,不是吗? “如您所见,每个字典键的第一个字母都没有大写。我怎样才能阻止这种情况发生?”
  • 不,我的问题与字典中的键有关,而不是字典名称。我需要它们不被格式化,即保持为“自定义属性 1”,而不是格式化为“自定义属性 1”

标签: c# json dictionary serialization json.net


【解决方案1】:

如演示小提琴 #1 here 中所示,仅使用问题中的代码不会重现问题。

相反,您必须使用JsonSerializerSettings.ContractResolver.NamingStrategy.ProcessDictionaryKeys = true 的一些全局序列化程序设置进行序列化,例如CamelCasePropertyNamesContractResolver

var settings = new JsonSerializerSettings
{
    ContractResolver = new CamelCasePropertyNamesContractResolver(),
};
var json = JsonConvert.SerializeObject(root, Formatting.Indented, settings);

演示小提琴 #2 here.

假设这是正确的,[JsonProperty(NamingStrategyType = typeof(SnakeCaseNamingStrategy), NamingStrategyParameters = new object[] { false, false })] 不会导致字典键被逐字序列化的原因是 JsonPropertyAttribute.NamingStrategyType 仅适用于 属性名称本身(此处为 CustomAttributes)而不是属性的项目的属性名称。如果您想对属性的项目应用命名策略,您需要类似 ItemNamingStrategyType 的东西——但 JsonPropertyAttribute 没有这样的功能。

那么,你有什么选择?

  1. 您可以修改全局命名策略以逐字序列化字典名称,如 Keep casing when serializing dictionaries 所示。

  2. 您可以将Dictionary&lt;TKey, TValue&gt; 子类化并将[JsonDictionary(NamingStrategyType = typeof(DefaultNamingStrategy))] 应用于它,如this answer 中所示Applying JsonDictionary attribute to dictionary

    [JsonDictionary(NamingStrategyType = typeof(DefaultNamingStrategy))]
    public class VerbatimDictionary<TKey, TValue> : Dictionary<TKey, TValue>
    {
    }
    

    然后:

    CustomAttributes = new VerbatimDictionary<string, string>()
    {
        {"Custom Attribute 1", "1"},
        {"CustomAttribute 2", "2"}
    }
    

    演示小提琴#3 here.

  3. 您可以引入一个custom JsonConverter,它使用默认命名策略序列化一个IDictionary&lt;TKey, TValue&gt;。首先,定义如下转换器:

    public class VerbatimDictionaryConverter<TKey, TValue> : JsonConverter<IDictionary<TKey, TValue>>
    {
        [JsonDictionary(NamingStrategyType = typeof(DefaultNamingStrategy))]
        class VerbatimDictionarySerializationSurrogate : IReadOnlyDictionary<TKey, TValue>
        {
            readonly IDictionary<TKey, TValue> dictionary;
    
            public VerbatimDictionarySerializationSurrogate(IDictionary<TKey, TValue> dictionary) 
            { 
                if (dictionary == null) 
                    throw new ArgumentNullException(nameof(dictionary));
                this.dictionary = dictionary; 
            }
            public bool ContainsKey(TKey key) { return dictionary.ContainsKey(key); }
            public bool TryGetValue(TKey key, out TValue value) { return dictionary.TryGetValue(key, out value); }
            public TValue this[TKey key] { get { return dictionary[key]; } }
            public IEnumerable<TKey> Keys { get { return dictionary.Keys; } }
            public IEnumerable<TValue> Values { get { return dictionary.Values; } }
            public int Count { get { return dictionary.Count; } }
            public IEnumerator<KeyValuePair<TKey, TValue>> GetEnumerator() { return dictionary.GetEnumerator(); }
            IEnumerator IEnumerable.GetEnumerator() { return GetEnumerator(); }
        }
    
        public override void WriteJson(JsonWriter writer, IDictionary<TKey, TValue> value, JsonSerializer serializer)
        {
            serializer.Serialize(writer, new VerbatimDictionarySerializationSurrogate(value));
        }
    
        public override bool CanRead { get { return false; } }
    
        public override IDictionary<TKey, TValue> ReadJson(JsonReader reader, Type objectType, IDictionary<TKey, TValue> existingValue, bool hasExistingValue, JsonSerializer serializer) { throw new NotImplementedException(); }
    }
    

    并应用如下:

    [JsonConverter(typeof(VerbatimDictionaryConverter<string, string>))]
    public IDictionary<string, string> CustomAttributes { get; set; }       
    

    演示小提琴 #4 here.

【讨论】:

    猜你喜欢
    • 2022-01-01
    • 2019-06-11
    • 2012-02-02
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多