JSON.NET转换为C#对象

7

我正在尝试在Windows窗体中使用JSON.NET框架从一个JSON字符串中读取一些信息。但是我无法获取'taxonomies->topics'数组和'clusters'中的字典。

{
    "keywords": {
        "anyString": [

        ],
        "allString": {
            "a5349f533e3aa3ccbc27de2638da38d6": "olympics"
        },
        "exactString": [

        ],
        "notString": [

        ],
        "highlightString": [

        ]
    },
    "dates": {
        "startDate": "15-01-2008",
        "endDate": "15-09-2009",
        "useDates": true
    },
    "clusters": {
        "permission": {
            "1": "private\/n"
        }
    },
    "taxonomies": {
        "Topics": {
            "2488": "Olympics 2012 (not participation)",
            "8876": "Olympics and culture"
        },
        "Keywords": {
            "8848": "Engineering in the Olympics"
        }
    },
    "sort": {
        "sortId": 1,
        "sortType": 2,
        "sort": "datetime",
        "sortOrder": "descending"
    }
}

使用下面的代码,我已经成功读取了一些信息。
JObject searchCriteria = JObject.Parse(contentSearchCriteria);  
//search criteria   
IEnumerable<string> allString = searchCriteria["keywords"]["allString"].Children().Values<string>();
IEnumerable<string> anyString = searchCriteria["keywords"]["anyString"].Children().Values<string>();
IEnumerable<string> notString = searchCriteria["keywords"]["notString"].Children().Values<string>();
IEnumerable<string> exactString = searchCriteria["keywords"]["exactString"].Children().Values<string>();
IEnumerable<string> highlightString = searchCriteria["keywords"]["highlightString"].Children().Values<string>();
//dates
string startDate = (string)searchCriteria["dates"]["startDate"];
string endDate = (string)searchCriteria["dates"]["endDate"];
bool useDates = (bool)searchCriteria["dates"]["useDates"];

//sort
int sortId = (int)searchCriteria["sort"]["sortId"];
int sortType = (int)searchCriteria["sort"]["sortType"];
string sort = (string)searchCriteria["sort"]["sort"];
string sortOrder = (string)searchCriteria["sort"]["sortOrder"];

更新:

根据建议,我添加了

class SMSearchCriteria
    {
        public SMKeywords keywords { get; set; }
        public SMDates dates { get; set; }
        public SMClusters clusters { get; set; }
        public SMTaxonomies taxonomies { get; set; }
        public SMSort sort { get; set; }
    }

    class SMKeywords
    {
        public List<Dictionary<string, string>> AnyString {get; set;}
        public List<Dictionary<string, string>> AllString { get; set; }
        public List<Dictionary<string, string>> ExactString { get; set; }
        public List<Dictionary<string, string>> NotString { get; set; }
        public List<Dictionary<string, string>> HighlightString { get; set; } 
    }

    class SMDates
    {
        public string startDate { get; set; }
        public string endDate { get; set; }
        public bool useDates { get; set; }
    }

    class SMClusters
    {
        List<SMCluster> cluster;
    }

    class SMCluster
    {
        public Dictionary<string, string> cluster { get; set; }
    }

     class SMTaxonomies
    {
         public List<SMTaxonomy> taxonomies { get; set; }
    }

     class SMTaxonomy
     {
         public Dictionary<string, List<SMCategory>> taxonomy { get; set; }
     }

     class SMCategory
     {
         public Dictionary<int, string> category { get; set; }
     }

     class SMSort
    {
        public int sortId { get; set; }
        public int sortType { get; set; }
        public string sort { get; set; }
        public string sortOrder { get; set; }
    }

但是当我执行以下命令时:
    var mydata = JsonConvert.DeserializeObject<SMSearchCriteria>(contentSearchCriteria);

我遇到了异常:

[Newtonsoft.Json.JsonSerializationException] = {"Cannot deserialize JSON object into type 'System.Collections.Generic.List`1[System.Collections.Generic.Dictionary`2[System.String,System.String]]'."}

更新2:

根据建议,我已删除所有额外的列表,并将类简化为以下内容:

class SearchMasterSearchCriteria
    {
        public SMKeywords keywords { get; set; }
        public SMDates dates { get; set; }
        public Dictionary<string, Dictionary<int, string>> clusters { get; set; } 
        public Dictionary<string, Dictionary<int, string>> taxonomies { get; set; } 
        public SMSort sort { get; set; }
    }

    class SMKeywords
    {
        public Dictionary<string, string> anyString {get; set;}
        public Dictionary<string, string> allString { get; set; }
        public Dictionary<string, string> exactString { get; set; }
        public Dictionary<string, string> notString { get; set; }
        public Dictionary<string, string> highlightString { get; set; } 
    }

    class SMDates
    {
        public string startDate { get; set; }
        public string endDate { get; set; }
        public bool useDates { get; set; }
    }

     class SMSort
    {
        public int sortId { get; set; }
        public int sortType { get; set; }
        public string sort { get; set; }
        public string sortOrder { get; set; }
    }

我还添加了测试代码,将对象序列化为以下形式:
//criteria
            SearchMasterSearchCriteria smCriteria = new SearchMasterSearchCriteria();

            //keywords
            SMKeywords smKeywords = new SMKeywords(); ;
            Dictionary<string, string> dict = new Dictionary<string, string>();
            dict.Add("a5349f533e3aa3ccbc27de2638da38d6", "olympics");
            dict.Add("9cfa7aefcc61936b70aaec6729329eda", "games");
            smKeywords.allString = dict;

            //category
            Dictionary<int, string> categorieDict = new Dictionary<int, string>();
            categorieDict.Add(2488, "Olympics 2012 (not participation)");
            categorieDict.Add(8876, "Olympics and culture");

            //taxonomies
            Dictionary<string, Dictionary<int, string>> taxonomiesDict = new Dictionary<string, Dictionary<int, string>>();
            taxonomiesDict.Add("Topics", categorieDict);

            //metadata
            Dictionary<int, string> metadataDict = new Dictionary<int, string>();
            metadataDict.Add(1, @"private/n");

            //clusters
            Dictionary<string, Dictionary<int, string>> clustersDict = new Dictionary<string, Dictionary<int, string>>();
            clustersDict.Add("permission", metadataDict);


            //dates
            SMDates smDates = new SMDates();
            smDates.startDate = "15-01-2008";
            smDates.endDate = "15-09-2009";
            smDates.useDates = true;

            //sort
            SMSort smSort = new SMSort();
            smSort.sortId = 1;
            smSort.sortType = 2;
            smSort.sort = "datetime";
            smSort.sortOrder = "descending";

           //add to criteria.
            smCriteria.keywords = smKeywords;
            smCriteria.clusters = clustersDict;
            smCriteria.taxonomies = taxonomiesDict;
            smCriteria.dates = smDates;
            smCriteria.sort = smSort;

            //serialize
            string json = JsonConvert.SerializeObject(smCriteria);
            var mydata1 = JsonConvert.DeserializeObject<SearchMasterSearchCriteria>(json);

那时候这2个json字符串唯一的区别是anyString,exactString等的[]和null。所以我替换了空方括号为大括号,然后反序列化没有出现错误 :)

contentSearchCriteria = contentSearchCriteria.Replace("[]", "{}");
var mydata = JsonConvert.DeserializeObject<SearchMasterSearchCriteria>(contentSearchCriteria);
4个回答

9
坦白地说,我根本不会像你一样这样做。这是我检索数据的方法:
class Data {
     Dictionary<string, Dictionary<string, string>> keywords;
     DatesClass dates;
     .......

}

class DatesClass
{
    string startDate;
    string endDate;
    bool? useDates

}


var mydata = JsonConvert.DeserializeObject<Data>(jsonstring);

我没有填写完整的数据类,但您明白了我的意思。我发现创建与输入数据结构相同的对象,然后使用DeserializeObject方法填充数据要容易得多。这也使代码更加清洁,并允许编译器检查拼写错误。


嗨,Timothy,我已按照你的建议使用类更新了问题。但是我遇到了一个异常。 - Benjamin Ortuzar

2

你现在的问题在于JSON.net如何反序列化对象。在JSON.net中,C#类变成了Json对象。而该类的成员变量则成为键,其值则成为对应的值。

以Taxonomy路径为例,使用你上面提供的类定义,JSON.net会按照以下格式查找Json数据:

{"taxonomies": {"taxonomies":[{"taxonomy": {"Topics": {1212, "foo"}}}]}

这看起来与您的输入数据完全不同。
在创建对象时,请考虑以下方式:
1)基本对象在JSON代码中创建{} 2)字典在JSON代码中创建{} 3)列表在JSON代码中创建[] 4)类的每个成员在JSON代码的{}中创建一个条目。
为了帮助您调试此问题,可以创建结构,填充一些临时数据,然后使用JsonConvert.Serialize(myobj)来显示JSON认为结构将是什么样子。
我认为您的异常来自于拥有过多的类。
这可能是您想要代码中分类部分的外观:
class SMSearchCriteria
{
        public SMKeywords keywords { get; set; }
        public SMDates dates { get; set; }
        public SMClusters clusters { get; set; }
        public SMTaxominies taxonomies { get; set; }
        public SMSort sort { get; set; }
}

class SMTaxominies
{
    public Dictionary<string, string> Topics;
    public Keywords<string, string> Keywords;
}

1

我会先从一个强类型的DTO类开始,最好是一个DataContract,这样你就可以选择将它序列化到任何格式中,如JSON、Xml、ProtoBuf等。

注意:与大多数其他格式相比(见:serialization benchmarks - JSON.NET是“NewtonSoft.Json”),JSON实际上序列化/反序列化起来相当慢。如果你正在做一个富客户端应用程序而不是Web应用程序,那么你可能想选择一个不同的序列化格式。无论你最终选择哪种格式,你仍然可以重复使用同一个DTO,例如,你上面的代码看起来会像这样:

[DataContract]
public class MyDto
{
  [DataMember]
  public Keywords keywords { get; set; }
}

[DataContract]
public class Keywords
{
  [DataMember]
  public List<string> anyString { get; set; }

  [DataMember]
  public Dictionary<string,string> allString { get; set; }

  [DataMember]
  public List<string> exactString { get; set; }

  [DataMember]
  public List<string> notString { get; set; }

  [DataMember]
  public List<string> highlightString { get; set; }
}

var dto = new MyDto { Keywords = { allString = {{"a5349f533e3aa3ccbc27de2638da38d6", "olympics"}} };

var json = JsonConvert.SerializeObject(dto);
var fromJson = JsonConvert.DeserializeObject<MyDto>(json);

编辑:添加了链接

看起来你可能在使用JSON.NET时遇到了问题,如果是这样,你应该尝试其他的JSON .NET序列化/反序列化器。微软在.NET v3.5中提供了一个System.Runtime.Serialization.Json.DataContractJsonSerializer。下面有一些辅助类,展示了如何序列化反序列化JSON。

Jayrock是另一个用于.NET的JSON序列化器,但它比其他的要慢,并且我发现它对泛型没有很好的支持。


我从一个我无法控制的系统接收到了JSON。我已经更新了问题并添加了新类,但是我仍然遇到了异常。 - Benjamin Ortuzar
好的,那么您可以使用仅包含Dictionary<string,string>和List<string>属性的松散类型的DTO模型吗? - mythz
你能给我一个例子吗?json.net 如何知道要映射到哪些属性? - Benjamin Ortuzar
实际上,我会做与您的更新相同的事情。为了帮助调试,请尝试反向操作,即填充对象并将其序列化为JSON,然后将结果与输入进行比较,以查看它们是否匹配。或者,尝试使用不同的JSON解析器,例如MS的JsonDataContractSerializer,我会在下面编辑并提供链接。 - mythz

0

为什么不使用LINQ to Json呢?

例如,将您的“sort”节点映射到您的类

var jsonResult = JObject.Parse(jsonString);

var sortItem = from s in jsonResult["sort"]
select new MySortObject{
                            SortId = s.Value<int>("sortId")
                        };

http://www.newtonsoft.com/json/help/html/QueryJsonLinq.htm


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接