gpt4 book ai didi

c# - JSON.NET 反序列化 - 单个结果与数组

转载 作者:行者123 更新时间:2023-12-04 00:33:06 32 4
gpt4 key购买 nike

我在尝试确定如何正确地使我的序列化能够访问单个结果以及数组时遇到问题。

当我进行 REST 调用以在服务器上查找某些内容时,有时它会返回一个模型数组,但如果搜索结果只有一个模型,则不会作为错误返回。这是当我收到一个无法反序列化的异常时,因为对象属性需要一个数组,而是接收一个对象。

有没有办法定义我的类,以便它可以在返回 ns1.models 类型的单个对象而不是对象数组时处理它?

[JsonObject]
public class Responses
{
[JsonProperty(PropertyName = "ns1.model")]
public List<Model> Model { get; set; }
}

可以反序列化的响应:
{"ns1.model":[
{"@mh":"0x20e800","ns1.attribute":{"@id":"0x1006e","$":"servername"}},
{"@mh":"0x21a400","ns1.attribute":{"@id":"0x1006e","$":"servername2"}}
]}

无法序列化的响应(因为 JSON 仅包含一个“ns1.model”):
{"ns1.model":
{"@mh":"0x20e800","ns1.attribute":{"@id":"0x1006e","$":"servername"}}
}

异常(exception):
Newtonsoft.Json.JsonSerializationException was unhandled   HResult=-2146233088   Message=Cannot deserialize the current JSON object (e.g. {"name":"value"}) into type 'System.Collections.Generic.List`1[ConsoleApplication1.Model]' because the type requires a JSON array (e.g. [1,2,3]) to deserialize correctly. To fix this error either change the JSON to a JSON array (e.g. [1,2,3]) or change the deserialized type so that it is a normal .NET type (e.g. not a primitive type like integer, not a collection type like an array or List<T>) that can be deserialized from a JSON object. JsonObjectAttribute can also be added to the type to force it to deserialize from a JSON object. Path '['ns1.model-response-list'].['ns1.model-responses'].['ns1.model'].@mh', line 1, position 130

最佳答案

要处理此问题,您必须使用自定义 JsonConverter。但你可能已经想到了这一点。
您只是在寻找可以立即使用的转换器。这提供的不仅仅是针对所描述情况的解决方案。
我举一个例子来说明问题。

如何使用我的转换器:

在属性上方放置一个 JsonConverter 属性。 JsonConverter(typeof(SafeCollectionConverter))

public class Response
{
[JsonProperty("ns1.model")]
[JsonConverter(typeof(SafeCollectionConverter))]
public List<Model> Model { get; set; }
}

public class Model
{
[JsonProperty("@mh")]
public string Mh { get; set; }

[JsonProperty("ns1.attribute")]
public ModelAttribute Attribute { get; set; }
}

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

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

这是我的转换器:
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
using System;

namespace stackoverflow.question18994685
{
public class SafeCollectionConverter : JsonConverter
{
public override bool CanConvert(Type objectType)
{
return true;
}

public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
{
//This not works for Populate (on existingValue)
return serializer.Deserialize<JToken>(reader).ToObjectCollectionSafe(objectType, serializer);
}

public override bool CanWrite => false;

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

此转换器使用以下类:
using System;

namespace Newtonsoft.Json.Linq
{
public static class SafeJsonConvertExtensions
{
public static object ToObjectCollectionSafe(this JToken jToken, Type objectType)
{
return ToObjectCollectionSafe(jToken, objectType, JsonSerializer.CreateDefault());
}

public static object ToObjectCollectionSafe(this JToken jToken, Type objectType, JsonSerializer jsonSerializer)
{
var expectArray = typeof(System.Collections.IEnumerable).IsAssignableFrom(objectType);

if (jToken is JArray jArray)
{
if (!expectArray)
{
//to object via singel
if (jArray.Count == 0)
return JValue.CreateNull().ToObject(objectType, jsonSerializer);

if (jArray.Count == 1)
return jArray.First.ToObject(objectType, jsonSerializer);
}
}
else if (expectArray)
{
//to object via JArray
return new JArray(jToken).ToObject(objectType, jsonSerializer);
}

return jToken.ToObject(objectType, jsonSerializer);
}

public static T ToObjectCollectionSafe<T>(this JToken jToken)
{
return (T)ToObjectCollectionSafe(jToken, typeof(T));
}

public static T ToObjectCollectionSafe<T>(this JToken jToken, JsonSerializer jsonSerializer)
{
return (T)ToObjectCollectionSafe(jToken, typeof(T), jsonSerializer);
}
}
}

它具体有什么作用?
如果您放置转换器属性,转换器将用于此属性。如果您希望 json 数组的结果为 1 或没有结果,则可以在普通对象上使用它。或者您在 IEnumerable 上使用它您期望 json 对象或 json 数组的位置。 (知道 array - object[] - 是 IEnumerable )
一个缺点是这个转换器只能放在一个属性上面,因为他认为他可以转换所有东西。和 被警告 . A string也是 IEnumerable .

它提供的不仅仅是这个问题的答案:
如果您按 id 搜索某些内容,您就会知道您将返回一个有结果或没有结果的数组。 ToObjectCollectionSafe<TResult>()方法可以为您处理。

这可用于使用 JSON.net 的 Single Result vs Array
并处理同一属性的单个项目和数组
并且可以将数组转换为单个对象。

我为服务器上的 REST 请求做了这个,过滤器在数组中返回一个结果,但希望将结果作为我的代码中的单个对象返回。并且还用于具有扩展结果的 OData 结果响应,其中包含一个数组中的一项。

玩得开心。

关于c# - JSON.NET 反序列化 - 单个结果与数组,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/27047875/

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