【问题标题】:JSON.NET parse optional values without try/catchJSON.NET 无需 try/catch 即可解析可选值
【发布时间】:2014-03-10 21:48:24
【问题描述】:

所以我一直工作的公司要求我为需要使用 .NET 访问我们的 API 的客户公司制作 C# 库。到目前为止,我有一个工作库,但我一直在解析可选属性时遇到问题。我们在后端使用 mongoDB,而 mongoDB 不会存储未提供的属性,即使它们是在架构中定义的。

例如,我的架构可能如下所示:

{
   name:String,
   id:Number,
   phone:String,
   email:String,
   experience:[]
}

我在哪里制作文档:

{
   name:"joe",
   id:5,
   phone:"222-222-2222",
}

属性emailexperience 在我的文档中不存在,所以我的JSON 看起来与上面显示的完全一样。然而,这些值不是必需的值,但我仍然需要解析它的其余部分。问题是,当我在解析emailexperience 时解析上面所有可能值的代码时,解析器会抛出空引用异常,这是有充分理由的,因为我试图解析的值不存在我引用这些值的方式是这样的:

JObject o=JObject.Parse(json); //parse json to JObject json object
string name=(string)o["name"];
int id=(int)o["id"];
string phone=(string)o["phone"];
string email=(string)o["emain"];
List<string> exp=o["experience"].Select(t => (string)t).ToList();

现在我的代码更加客观,我使用 LINQ 创建了一个名为 Job 的对象和一个对象 Jobs 以存储 JObject 的方式,您可以使用 @ 的方法从中查询某些值987654330@ 使用原始 JSON 字符串初始化的对象。

我能想到的在 JSON 中处理可选属性的唯一方法是尝试/捕获每个值。这看起来很草率,我必须解析的 JSON 总共大约有 40-50 个属性。这似乎会非常缓慢并且代码混乱。我想知道我是否可以实现这是一种更清洁更有效的方式。

【问题讨论】:

  • 你试过var job = JsonConvert.DeserializeObject&lt;Job&gt;(json);吗?
  • 我不确定我是否理解。 MongoDB 是无模式的,对吧?你不应该解析任何东西。您可以将其作为 BSON 文档转储到 Mongo 中
  • @mason 它是 Json.Net 的类。
  • @tsturzl 看来你错过了一些东西。 转到 first_comment;
  • @tsturzl 你的问题在于你试图手动反序列化,那么这是 Json.NET 开箱即用的东西,就像第一条评论和埃文的回答一样。

标签: c# json linq json.net


【解决方案1】:

除非有充分的理由您不能使用通用的反序列化/序列化方法,否则我建议您更改使用这些方法的方法。一般来说,我认为您在上面所做的条件性、特定于属性的解析类型是非常糟糕的做法。这是一个例子;

public class Job
{
   public string name;
   public string id;
   public string phone;
   public string email;
   public string[] experience; // can also be a List<string> without any problems
}

Job j = JsonConvert.DeserializeObject<Job>(jsonString);

string output = JsonConvert.SerializeObject(j);
//will include "optional" parameters, meaning if there is no phone value it will be an empty string but the property name will still be there.

如果你真的想确认一下,包括一些必需的参数,但不包括其他一些可选参数,我建议将 json 模式与 json.NET 结合使用。您可以执行以下操作;

//schema in flat text file I read with File.ReadAllText(path);
{
    "type":"object",
    "$schema": "http://json-schema.org/draft-03/schema",
    "required":true,
    "properties":{
        "name": { "type":"string", "required":true },
        "id": { "type":"string", "required":true },
                "phone": { "type":"string", "required":false },
                "email": { "type":"string", "required":false },
                "experience": { "type":"array", "required":true, "items": { "string" } }
    }
}

然后在代码中你有类似的东西;

JObject obj = JObject.Parse(json);
JsonSchema jscheme = JsonSchema.Parse(File.ReadAllText(thatSchemaAbove));
IList<string> errors;
obj.IsValid(jscheme, out errors);
if (errors.Count() > 0)
{
     //json didn't match the schema, do something about it!
}

编辑:处理复杂对象;

假设您的 json 是一个对象,其中包含一个名为 jobsJob 对象数组。为此使用以下 C# 类定义;

public class jobsWrapper
{
    public List<Job> jobs;
}

json 中使用的任何构造都有一个 C# 等价物,您只需分解它并确定它是什么。

【讨论】:

  • 谢谢 C# 绝对不是我的强项。如果我想将体验设置为 List 而不是数组,那会有问题吗?
  • @tsturzl 一点也不。只要在你的课堂上做到这一点,一切都会照常进行。
  • 如何解析嵌入的对象?我有嵌入在数组中的对象,以及其他对象中的对象。这个 JSON 相当复杂。
  • @tsturzl 所以它只是将 json 中的数据模型转换为 C# 中的类。我将使用另一个小 sn-p 进行编辑,这可能会让您朝着正确的方向前进。我会包含更多细节,但这很乏味,而且由于显而易见的原因,我无法复制/粘贴任何实际工作。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2010-09-14
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多