【问题标题】:JSON string to model / HashMap/ Dictionary in C#JSON字符串在C#中建模/HashMap/字典
【发布时间】:2018-01-16 18:14:17
【问题描述】:

我有 JSON:

{
"One": [
{
  "ID": 1,
  "name": "s"
},
{
  "categoryID": 2,
  "name": "c"
}
],
"Two": [
{
  "ID": 3,
  "name": "l"
}
],
"Three": [
{
  "ID": 8,
  "name": "s&P"
},
{
  "ID": 52,
  "name": "BB"
}
]
}

我想:

  1. 将此 JSON 带到任何对象(如 JObject)

  2. 在不同的条件下过滤 JSON(如名称以 s 开头等)

  3. 将此 JSON 返回给客户端

我尝试过的事情: 1. 创建模型:

class Model
{
public int Id;
public string name;
}
class MainModel
{
public string mainName;
public List<Model> categories;
}

并使用这些模型:

List<MainModel> m = json_serializer.DeserializeObject(jsonString);
  1. 我也尝试了 Dictionary,但无法投射异常。

任何帮助将不胜感激。

【问题讨论】:

  • 你试过Dictionary&lt;string, List&lt;Model&gt;&gt;吗?
  • var jObj = JObject.Parse(jsonString); 现在您拥有的不仅仅是一本字典。 newtonsoft.com/json/help/html/…
  • 我试过 Dictionary: Dictionary> dct = (Dictionary >) json_serializer.DeserializeObject(json);我收到无效的演员表异常
  • 显然你会得到无效的强制转换异常。你的模型与 JSON 不一致

标签: c# json dictionary hashmap


【解决方案1】:

我编写了这段代码,假设:

  • OneTwoThreeMainCategory - 从 KeyValuePair&lt;string name, List&lt;SubCategory&gt; values&gt; 序列化为 JProperty。长类型名称,嗯?如果您想经常使用结果字典,请添加以下内容:

    using MainCategories = System.Collections.Generic.Dictionary<string, System.Collections.Generic.List<JsonDeSerializtionTest.SubCategory>>;
    
  • categoryIDID 是描述为 Id 的属性,不能在同一个 SubCategory 上共存,但可以更改 SubCategory 的类型。

1。创建SubCategory 类:

public class SubCategory
{
    [JsonIgnore]
    public DataTypes DataType { get; set; }

    [JsonIgnore]
    public string Parent { get; set; }

    [JsonProperty("ID")]
    public int Id { get; set; }

    [JsonProperty("categoryID")]
    public int CategoryId => Id;

    [JsonProperty("name")]
    public string Name { get; set; }

    public bool ShouldSerializeId()
    {
        return DataType == DataTypes.Id;
    }

    public bool ShouldSerializeCategoryId()
    {
        return DataType == DataTypes.CategoryId;
    }

}

2。创建Deserialize(string json)函数:

private static MainCategories Deserialize(string json)
{
    Dictionary<string, List < SubCategory >> jsonBody = new Dictionary<string, List<SubCategory>>();

    JObject jObject = JObject.Parse(json);
    // the outer object {one...two..}

    foreach (KeyValuePair<string, JToken> jMainCategory in jObject)
    {
        // jMainCategory => "one": [{...}, {...}]
        string key = jMainCategory.Key;
        List<SubCategory> values = new List<SubCategory>();
        foreach (JObject jSubCategory in jMainCategory.Value)
        {
            //jsubCategory => {"name" : ..., "ID": ... }
            SubCategory subCategory = new SubCategory();

            JToken idProperty;
            if (jSubCategory.TryGetValue("ID", out idProperty))
            {
                subCategory.DataType = DataTypes.Id;
                subCategory.Id = idProperty.Value<int>();
            }
            else
            {
                subCategory.DataType = DataTypes.CategoryId;
                subCategory.Id = jSubCategory["categoryID"].Value<int>();
            }

            subCategory.Name = jSubCategory["name"].Value<string>();
            subCategory.Parent = key;
            // subCategory.AnotherProperty = jSubCategory["anotherproperty"].Value<type>();

            values.Add(subCategory);
        }
        jsonBody.Add(key, values);
    }
    return jsonBody;
}

3。使用该函数获取可用于排序和过滤的Dictionary&lt;string, List&lt;SubCategory&gt;&gt;。示例:

public static MainCategories WhereNameStartsWith(this MainCategories jsonBody, string str)
{
    MainCategories result = new MainCategories();
    //if you want to keep the result json structure `as is` return a MainCategories object

    foreach (var subCategory in jsonBody.SelectMany(mainCategory => mainCategory.Value).Where(subCategory => subCategory.Name.StartsWith(str)))
    {
        if(result.ContainsKey(subCategory.Parent))
            result[subCategory.Parent].Add(subCategory);
        else
            result.Add(subCategory.Parent, new List<SubCategory> {subCategory});
    }
    // if you just want the subcategories matching the condition create a WhereListNameStartsWith method
    // where `result` is a list of subcategories matching the condition
    return  result;
}    

上行:

  • 不要玩 NewtonSoft JsonConverter 或 ContractResolvers。

  • 使用 LINQ 轻松排序 NameCategoryId/Id 的能力相同,但 SubCategory.DataType 不同:

    foreach (var subCategory in jsonBody.SelectMany(mainCategory => mainCategory.Value).Where(subCategory => subCategory.DataType == DataTypes.CategoryId))
    
  • 您可以轻松地将 JSON 序列化回字符串表示形式。示例:

    string jsonIn ="{\"One\":[{\"ID\":1,\"name\":\"s\"}," +
                                 "{\"categoryID\":2,\"name\":\"c\"}]," +
                    "\"Two\":[{\"ID\":3,\"name\":\"l\"}]," +
                    "\"Three\":[{\"ID\":8,\"name\":\"s&P\"}," +
                                  "{\"ID\":52,\"name\":\"BB\"}]}";
    MainCategories desrializedJson = Deserialize(jsonIn);
    MainCategories filtered = desrializedJson.WhereNameStartsWith("s");
    string jsonOut = JsonConvert.SerializeObject(desrializedJson, Formatting.None);
    Debug.Assert(jsonOut == jsonIn); //true
    
  • 在访问 Id/CategoryId 时无需进行空值检查。

  • 我的最爱:对属性名称使用 C# 语法。

缺点:

  • 我不知道。这是一个粘贴然后忘记的解决方案:P

    在更改 JSON 结构时可能会更困难(尽管我可能会认为这会让事情变得更容易)

注意事项:

  • Parent 是可选的,用于在使用 LINQ 时使事情变得更容易
  • DataTypes 是一个枚举,用于确定是否找到了IDcategoryID,如果您需要此类信息,还可以序列化正确的属性(相同的双向转换)

    public enum DataTypes
    {
        Id,
        CategoryId
    };
    

【讨论】:

    【解决方案2】:

    以下将允许您将 JSON 反序列化为字典并对其进行过滤。这使用 Newtonsoft.Json Nuget 包,但这很常见。代码贴在下面。在这里找到工作示例.Net Fiddle

    using System;
    using Newtonsoft.Json;
    using System.Collections.Generic;
    using System.Linq;
    
    
    public class Program
    {
        public static void Main()
        {
            var json = "{\"One\": [{  \"ID\": 1,  \"name\": \"s\"},{  \"categoryID\": 2,  \"name\": \"c\"}],\"Two\": [{  \"ID\": 3,  \"name\": \"l\"}],\"Three\": [{  \"ID\": 8,  \"name\": \"s&P\"},{  \"ID\": 52,  \"name\": \"BB\"}]}";      
            var deserialized = JsonConvert.DeserializeObject<Dictionary<string, List<Model>>>(json);
    
            Console.WriteLine(deserialized["One"][0].name);
    
            Console.WriteLine("Filter to starts with s");
            var filtered = deserialized.SelectMany(item => item.Value).Where(innerItem => innerItem.name.StartsWith("s"));
            foreach(var item in filtered){
                Console.WriteLine(item.name);   
            }
    
        }
    
        public class Model{
            public int ID {get;set;}
            public string name {get;set;}
            public int categoryID {get;set;}
        }
    }
    

    【讨论】:

      猜你喜欢
      • 2014-03-27
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2011-08-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多