【问题标题】:Serialize List<KeyValuePair<string, string>> as JSON将 List<KeyValuePair<string, string>> 序列化为 JSON
【发布时间】:2017-05-21 01:23:50
【问题描述】:

我是 JSON 新手,请帮忙!

我正在尝试将List&lt;KeyValuePair&lt;string, string&gt;&gt; 序列化为 JSON

目前:

[{"Key":"MyKey 1","Value":"MyValue 1"},{"Key":"MyKey 2","Value":"MyValue 2"}]

预期:

[{"MyKey 1":"MyValue 1"},{"MyKey 2":"MyValue 2"}]

我参考了this和this的一些例子。

这是我的 KeyValuePairJsonConverter : JsonConverter

public class KeyValuePairJsonConverter : JsonConverter
{
    public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
    {
        List<KeyValuePair<object, object>> list = value as List<KeyValuePair<object, object>>;
        writer.WriteStartArray();
        foreach (var item in list)
        {
            writer.WriteStartObject();
            writer.WritePropertyName(item.Key.ToString());
            writer.WriteValue(item.Value.ToString());
            writer.WriteEndObject();
        }
        writer.WriteEndArray();
    }

    public override bool CanConvert(Type objectType)
    {
        return objectType == typeof(List<KeyValuePair<object, object>>);
    }

    public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
    {
        var jsonObject = JObject.Load(reader);
        var target = Create(objectType, jsonObject);
        serializer.Populate(jsonObject.CreateReader(), target);
        return target;
    }

    private object Create(Type objectType, JObject jsonObject)
    {
        if (FieldExists("Key", jsonObject))
        {
            return jsonObject["Key"].ToString();
        }

        if (FieldExists("Value", jsonObject))
        {
            return jsonObject["Value"].ToString();
        }
        return null;
    }

    private bool FieldExists(string fieldName, JObject jsonObject)
    {
        return jsonObject[fieldName] != null;
    }
}

我是从这样的 WebService 方法调用它

List<KeyValuePair<string, string>> valuesList = new List<KeyValuePair<string, string>>();
Dictionary<string, string> valuesDict = SomeDictionaryMethod();

foreach(KeyValuePair<string, string> keyValue in valuesDict)
{
    valuesList.Add(keyValue);
}

JsonSerializerSettings jsonSettings = new JsonSerializerSettings { Converters = new [] {new KeyValuePairJsonConverter()} };
string valuesJson = JsonConvert.SerializeObject(valuesList, jsonSettings);

【问题讨论】:

  • 请尝试将 ´objectType == typeof(List>);´ 更改为 ´objectType == typeof(List>);´ in CanConvert 方法
  • 一个问题 - 你为什么使用 KeyValuePairs 列表而不是 Dictionary?
  • @SergeyBerezovskiy 你是对的!我想我在谷歌搜索使用什么时迷路了,最终把事情复杂化了。谢谢!

标签: c# json keyvaluepair


【解决方案1】:

您可以使用 Newtonsoft 和字典:

    var dict = new Dictionary<int, string>();
    dict.Add(1, "one");
    dict.Add(2, "two");

    var output = Newtonsoft.Json.JsonConvert.SerializeObject(dict);

输出是:

{"1":"one","2":"two"}

编辑

感谢 @Sergey Berezovskiy 提供信息。

您当前正在使用 Newtonsoft,因此只需将您的 List&lt;KeyValuePair&lt;object, object&gt;&gt; 更改为 Dictionary&lt;object,object&gt; 并使用包中的序列化和反序列化方法。

【讨论】:

  • 所以他只需要将 List> 更改为 Dictionnary。我将编辑我的答案
  • 这是我在 cmets 中问他的。并非总是可以将 KeyValuePairs 列表更改为字典。示例 - 您可以使用 KVP 传递键值作为元组或创建类的替代方法。并且您可以拥有许多具有相同 Key 的键值对。字典不是这样。
  • 在他的创建方法中,如果密钥已经存在,他会更改,所以我认为我们更多的是在需要字典的场景中,但你完全正确的是在某些情况下这种列表可能很有用: )
  • @OrcusZ 感谢您的帮助!我删除了 List> 以简单地 Dictionary 和序列化就可以了。
  • 当你知道它的时候就这么简单。谢谢。这个答案将大大受益于解释为什么...... keyvaluepair 与字典有何不同来解释序列化行为的这种差异?
【解决方案2】:

所以我不想使用除本机 c# 之外的任何东西来解决类似的问题,作为参考,这是使用 .net 4、jquery 3.2.1 和骨干网 1.2.0。

我的问题是List&lt;KeyValuePair&lt;...&gt;&gt; 会从控制器处理成主干模型,但是当我保存该模型时,控制器无法绑定列表。

public class SomeModel {
    List<KeyValuePair<int, String>> SomeList { get; set; }
}

[HttpGet]
SomeControllerMethod() {
    SomeModel someModel = new SomeModel();
    someModel.SomeList = GetListSortedAlphabetically();
    return this.Json(someModel, JsonBehavior.AllowGet);
}

网络捕获:

"SomeList":[{"Key":13,"Value":"aaab"},{"Key":248,"Value":"aaac"}]

但是,即使在支持 model.js 中正确设置 SomeList 尝试保存模型而不对其进行任何更改也会导致绑定 SomeModel 对象与请求正文中的参数具有相同的长度,但所有键和值为空:

[HttpPut]
SomeControllerMethod([FromBody] SomeModel){
    SomeModel.SomeList; // Count = 2, all keys and values null.
}

我唯一能找到的是 KeyValuePair 是一个结构,而不是可以以这种方式实例化的东西。我最终做的是以下内容:

  • 在某处添加包含键、值字段的模型包装器:

    public class KeyValuePairWrapper {
        public int Key { get; set; }
        public String Value { get; set; }
    
        //default constructor will be required for binding, the Web.MVC binder will invoke this and set the Key and Value accordingly.
        public KeyValuePairWrapper() { }
    
        //a convenience method which allows you to set the values while sorting
        public KeyValuePairWrapper(int key, String value)
        {
            Key = key;
            Value = value;
        }
    }
    
  • 设置您的绑定类模型以接受您的自定义包装对象。

    public class SomeModel
    {
        public List<KeyValuePairWrapper> KeyValuePairList{ get; set }; 
    }
    
  • 从控制器中获取一些 json 数据

    [HttpGet]
    SomeControllerMethod() {
        SomeModel someModel = new SomeModel();
        someModel.KeyValuePairList = GetListSortedAlphabetically();
        return this.Json(someModel, JsonBehavior.AllowGet);
    }
    
  • 稍后再做一些事情,也许会调用 model.save(null, ...)

    [HttpPut]
    SomeControllerMethod([FromBody] SomeModel){
        SomeModel.KeyValuePairList ; // Count = 2, all keys and values are correct.
    }
    

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-01-15
    • 2020-05-06
    • 2014-02-08
    • 1970-01-01
    相关资源
    最近更新 更多