gpt4 book ai didi

c# - JsonConvert.DeserializeObject<>(字符串)返回 $id 属性的空值

转载 作者:太空狗 更新时间:2023-10-29 18:22:21 24 4
gpt4 key购买 nike

我正在使用 System.Net.WebClient.DownloadString 下载 JSON。我得到了一个有效的回应:

{
"FormDefinition": [
{
"$id":"4",
"Class":558,
"ClassDisplayLabel":"Punchworks",
"Name":"Punchworks Form"
},
{
"$id":"6",
"Class":558,
"ClassDisplayLabel":"Punchworks",
"Name":"Punchworks Form test second"
},
{
"$id":"46",
"Class":558,
"ClassDisplayLabel":"Punchworks",
"Name":"any_Name"
},
{
"$id":"47",
"Class":558,
"ClassDisplayLabel":"Punchworks",
"Name":"Punchworks Form test second"
},
{
"$id":"49",
"Class":558,
"ClassDisplayLabel":"Punchworks",
"Name":"Testing Name ??´????? ???? ACEeišuu { [ ( ~ ! @ # "
},
{
"$id":"50",
"Class":558,
"ClassDisplayLabel":"Punchworks",
"Name":"something new"
},
{
"$id":"56",
"Class":558,
"ClassDisplayLabel":"Punchworks",
"Name":"Testing Name руÌÑÑкий 汉语漢語 ĄČĘėįšųū { [ ( ~ ! @ # "
},
{
"$id":"57",
"Class":558,
"ClassDisplayLabel":"Punchworks",
"Name":"Test Name"
},
{
"$id":"58",
"Class":558,
"ClassDisplayLabel":"Punchworks",
"Name":"Unique Name - 12/16/2013 12:59:29 PM"
},
{
"$id":"59",
"Class":558,
"ClassDisplayLabel":"Punchworks",
"Name":"Unique Name - 12/16/2013 1:01:18 PM"
},
{
"$id":"60",
"Class":558,
"ClassDisplayLabel":"Punchworks",
"Name":"Unique Name - 12/16/2013 1:40:44 PM"
},
{
"$id":"61",
"Class":558,
"ClassDisplayLabel":"Punchworks",
"Name":"Unique Name - 12/16/2013 1:43:46 PM"
},
{
"$id":"62",
"Class":558,
"ClassDisplayLabel":"Punchworks",
"Name":"Unique Name - 12/16/2013 1:48:21 PM"
},
{
"$id":"63",
"Class":558,
"ClassDisplayLabel":"Punchworks",
"Name":"Unique Name - 12/16/2013 1:57:00 PM"
},
{
"$id":"64",
"Class":558,
"ClassDisplayLabel":"Punchworks",
"Name":"Unique Name - 12/16/2013 1:57:53 PM"
},
{
"$id":"65",
"Class":558,
"ClassDisplayLabel":"Punchworks",
"Name":"Unique Name - 12/16/2013 1:58:46 PM"
},
{
"$id":"79",
"Class":558,
"ClassDisplayLabel":"Punchworks",
"Name":"Testing Name1211"
},
{
"$id":"80",
"Class":558,
"ClassDisplayLabel":"Punchworks",
"Name":"Testing Name1211"
},
{
"$id":"81",
"Class":558,
"ClassDisplayLabel":"Punchworks",
"Name":"any_nami"
},
{
"$id":"90",
"Class":558,
"ClassDisplayLabel":"Punchworks",
"Name":"Test_something3"
},
{
"$id":"91",
"Class":558,
"ClassDisplayLabel":"Punchworks",
"Name":"Test_something4"
}]
}

这是我的模型:

public class FormDefinitionList
{
[JsonProperty("FormDefinition")]
public List<FormDefinition> FormDefinitions { get; set; }
}

public class FormDefinition
{
[JsonProperty ("$id")]
public string Id { get; set; }

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

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

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

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

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

当我这样做时一切正常:

string response = "json as above";
FormDefinitionList root = JsonConvert.DeserializeObject<FormDefinitionList> (response);

除了 Id ($id) 属性始终为空。起初我试图弄清楚我从服务器返回的美元符号是否不同,但情况似乎并非如此。我不确定从这里到哪里去,所以有什么想法吗?

提前致谢。

注意:如果我尝试使用 JavaScriptSerializer 之类的东西反序列化,它会完美运行,所以我相当确定我的模型或 JSON.net 有问题。虽然可能是错误的。

最佳答案

Json.Net 通常使用 $id连同 $ref作为元数据来保存 JSON 中的对象引用。所以当它看到 $id它假定属性不是实际 JSON 属性集的一部分,而是一个内部标识符。因此它不会填充 Id你的对象的属性,即使你包含了一个[JsonProperty]属性表明它应该。

更新

截至 Json.Net 版本6.0.4 ,有一个新设置,您可以通过该设置指示反序列化器将这些“元数据”属性视为普通属性,而不是使用它们。您需要做的就是设置 MetadataPropertyHandling设置为 Ignore然后照常反序列化。

var settings = new JsonSerializerSettings();
settings.MetadataPropertyHandling = MetadataPropertyHandling.Ignore;

var obj = JsonConvert.DeserializeObject<FormDefinitionList>(json, settings);

在版本 6.0.4 之前,需要一种变通方法来解决此问题。该答案的其余部分讨论了可能的解决方法。如果您使用的是 6.0.4 或更高版本,则不需要解决方法,现在可以停止阅读。


我能看到的最简单的解决方法是对 "$id" 进行字符串替换与 "id" (包括引号)在反序列化之前在 JSON 上,正如@Carlos Coelho 所建议的那样。由于您必须对每个响应都执行此操作,如果您走这条路,我建议您制作一个简单的辅助方法来避免代码重复,例如:

public static T Deserialize<T>(string json)
{
return JsonConvert.DeserializeObject<T>(json.Replace("\"$id\"", "\"id\""));
}

但是,由于您在评论中表示您不太热衷于使用字符串替换的想法,因此我研究了其他选项。我确实找到了另一种可能适合您的替代方案——自定义 JsonConverter .转换器背后的想法是,它将尝试使用 Json.Net 的内置反序列化机制来创建和填充对象(无 ID),然后手动检索 $id。来自 JSON 的属性并使用它来填充 Id通过反射在对象上的属性。

这是转换器的代码:

public class DollarIdPreservingConverter : JsonConverter
{
public override bool CanConvert(Type objectType)
{
return objectType == typeof(FormDefinition);
}

public override object ReadJson(JsonReader reader, Type objectType,
object existingValue, JsonSerializer serializer)
{
JObject jo = JObject.Load(reader);
object o = jo.ToObject(objectType);
JToken id = jo["$id"];
if (id != null)
{
PropertyInfo prop = objectType.GetProperty("Id");
if (prop != null && prop.CanWrite &&
prop.PropertyType == typeof(string))
{
prop.SetValue(o, id.ToString(), null);
}
}
return o;
}

public override void WriteJson(JsonWriter writer, object value,
JsonSerializer serializer)
{
throw new NotImplementedException();
}
}

我尝试编写转换器,使其适用于任何具有 $id 的对象-- 你只需要改变 CanConvert相应的方法,以便除了 FormDefinition 之外,它还为您需要使用它的所有类型返回 true .

要使用转换器,您只需将它的实例传递给 DeserializeObject<T>像这样:

FormDefinitionList root = JsonConvert.DeserializeObject<FormDefinitionList>(
json, new DollarIdPreservingConverter());

重要提示:您可能会想用 JsonConverter 来装饰您的类。属性而不是将转换器传递给 DeserializeObject调用,但不要这样做——它会导致转换器进入递归循环,直到堆栈溢出。 (有一种方法可以让转换器使用属性,但您必须重写 ReadJson 方法以手动创建目标对象并填充其属性,而不是调用 jo.ToObject(objectType) 。这是可行的,但有点更乱。)

让我知道这是否适合您。

关于c# - JsonConvert.DeserializeObject<>(字符串)返回 $id 属性的空值,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/20686336/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com