【问题标题】:Pull JObject property from JObject that has specific other property value从具有特定其他属性值的 JObject 中提取 JObject 属性
【发布时间】:2019-10-26 01:19:50
【问题描述】:

我对 json.net 的使用相对流利,但我很难以一种直接的方式提取这个值。

我觉得 json.net 应该能够推断出我正在尝试做的事情,这样我就不必一路走来获得我想要的东西。

下面是我第一次失败的尝试和第二次我开始工作的尝试。虽然第二次尝试确实有效,但我想简化代码,使其更像第一次。

请注意,我不能假设“C”对象是包含我想要的对象的对象。

var jt = JToken.Parse(@"{
    ""A"": {
        ""name"": ""object1"",
        ""order"": ""1"",
        ""type"": ""val""
    },
    ""B"": {
        ""order"": ""2"",
        ""type"": ""val"",

    },
    ""C"": {
        ""name"": ""object3"",
        ""type"": ""val"",
        ""answer"": ""Yes"", ""<------ comment"": ""this is the value I'm trying to get""
    }
}");

//var firstAttempt = (jt.First(j => j["name"] == "object3"))["answer"];  // cannot be applied to operands of type 'JToken' and 'String'

var thisWorksFine = jt.First(a => a.ToObject<JProperty>()
                            .Value.ToObject<JObject>()["name"]?.ToString() == "object3")
                            .ToObject<JProperty>()
                            .Value["answer"];

所以我的问题是,有没有一种方法可以在不必强制转换每个对象/属性的情况下获得价值,并最终获得看起来更像我第一次尝试的代码?如果我的第二次尝试或多或少是必须要做的,那很好。

【问题讨论】:

  • 谢谢大家,我添加了一个注释,我不想假设对象 C 包含我想要的值,因为它可能会改变。
  • 只需反序列化为模型......

标签: c# json json.net


【解决方案1】:

我使用QuickType 为您的 Json 代码制作模型,然后对其进行解析并对生成的对象进行过滤,这更容易。 代码:

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

    [JsonProperty("order")]
    public long Order { get; set; }

    [JsonProperty("type")]
    public string Type { get; set; }

    [JsonProperty("answer")]
    public string Answer { get; set; }
}

并解析:

string json = @"{
    ""A"": {
        ""name"": ""object1"",
        ""order"": ""1"",
        ""type"": ""val""
    },
    ""B"": {
        ""order"": ""2"",
        ""type"": ""val"",

    },
    ""C"": {
        ""name"": ""object3"",
        ""type"": ""val"",
        ""answer"": ""Yes"",
    }
}";

Dictionary<string, MyElement> elements = JsonConvert.DeserializeObject<Dictionary<string, MyElement>>(json);
string answerOfObject3 = elements.Values.FirstOrDefault(element => element.Name == "object3")?.Answer;

【讨论】:

  • 感谢 @MindSwipe 向我展示 QuickType,这很棒!
  • chris 的建议,如果您需要答案 C,您也可以使用 elements["C"].Answer
  • 很有趣,谢谢。我不确定我是否要为此目的创建一个类,但它的一些变体可能对我有用。
【解决方案2】:

您是否特别希望始终在“C”对象下获得答案?

如果是这样,您可以使用:

var jToken = JToken.Parse("{\r\n\t\"A\": {\r\n\t\t\"name\": \"object1\",\r\n\t\t\"order\": \"1\",\r\n\t\t\"type\": \"val\"\r\n\t},\r\n\t\"B\": {\r\n\t\t\"name\": \"object2\",\r\n\t\t\"order\": \"2\",\r\n\t\t\"type\": \"val\"\r\n\t},\r\n\t\"C\": {\r\n\t\t\"name\": \"object3\",\r\n\t\t\"type\": \"val\",\r\n\t\t\"answer\": \"Yes\"\r\n\t}\r\n}");

var answer = jToken.SelectToken("C.answer");

【讨论】:

  • 它可能并不总是 C,但有趣的是我不知道 SelectToken,谢谢。
  • @Jordan 它会一直在名为“object3”的对象下吗?
  • 对,是的,我总是想要包含名称“object3”的对象的答案值。
【解决方案3】:

您似乎跳过了比您需要的更多的圈子。我会这样重写你的查询:

var answer = jt.Children<JProperty>()
               .Where(jp => (string)jp.Value["name"] == "object3")
               .Select(jp => (string)jp.Value["answer"])
               .FirstOrDefault();

小提琴:https://dotnetfiddle.net/blKne6

上面可以稍微简化为以下,这更接近你的第一次尝试:

var answer = (string)jt.Children<JProperty>()
                       .FirstOrDefault(jp => (string)jp.Value["name"] == "object3")
                       ?.Value["answer"];

小提琴:https://dotnetfiddle.net/3Iw8Uu

【讨论】:

  • 很好,谢谢布赖恩,是的,这绝对更干净,我之前没有使用过.Children,所以我会把它添加到我的工具带中。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2022-09-30
  • 1970-01-01
  • 2017-08-31
相关资源
最近更新 更多