将JSON反序列化为c#: string和string[]值
本文关键字:string JSON 反序列化 | 更新日期: 2023-09-27 17:50:15
我需要从REST服务中使用JSON。对于其中一个字段,服务有时为该值返回字符串,而其他时候为该值返回字符串数组。
例如:var jsonArrayResponse = "{ '"id'" : '"abc'", '"relatedIds'" : [ '"def'", '"ghi'", '"jkl'" ] }";
var jsonSingleResponse = "{ '"id'" : '"123'", '"relatedIds'" : '"456'" }";
我已经实现了目标类使用SingleValueArrayConverter模式在这篇文章中找到。下面是完整的代码集来说明我的问题:
class Program
{
static void Main(string[] args)
{
// this works fine with the SingleValueArrayConverter
var jsonArray = "{ '"id'" : '"abc'", '"relatedIds'" : [ '"def'", '"ghi'", '"jkl'" ] }";
var objArray = (MyObject)JsonConvert.DeserializeObject(jsonArray, typeof(MyObject));
// this fails to parse "456" with Exception message:
// "Unable to cast object of type 'System.Object' to
// type 'System.Collections.Generic.List`1[System.String]'."
var jsonSingle = "{ '"id'" : '"123'", '"relatedIds'" : '"456'" }";
var objSingle = (MyObject)JsonConvert.DeserializeObject(jsonSingle, typeof (MyObject));
}
}
[DataContract]
public class MyObject
{
[DataMember(Name = "id")]
public string Id;
[DataMember(Name = "relatedIds")]
[JsonConverter(typeof(SingleValueArrayConverter<string>))]
public List<string> RelatedIds;
}
public class SingleValueArrayConverter<T> : JsonConverter
{
public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
{
serializer.Serialize(writer, value);
}
public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
{
object retVal = new Object();
if (reader.TokenType == JsonToken.StartObject)
{
T instance = (T)serializer.Deserialize(reader, typeof(T));
retVal = new List<T>() { instance };
}
else if (reader.TokenType == JsonToken.StartArray)
{
retVal = serializer.Deserialize(reader, objectType);
}
return retVal;
}
public override bool CanConvert(Type objectType)
{
return false;
}
}
我怎么能解决这个问题,正确解析两个不同的JSON blob到同一个类?
更新:
我修改了SingleValueArrayConverter来检查字符串大小写(如下所述),事情开始工作了。我使用的转换器不仅仅是字符串,所以我必须添加第一个if语句,而不是像建议的那样修改它)。
public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
{
object retVal = new Object();
if (reader.TokenType == JsonToken.String)
{
string instance = (string)serializer.Deserialize(reader);
retVal = new List<string> () {instance};
}
else if (reader.TokenType == JsonToken.StartObject)
{
T instance = (T)serializer.Deserialize(reader, typeof(T));
retVal = new List<T>() { instance };
}
else if (reader.TokenType == JsonToken.StartArray)
{
retVal = serializer.Deserialize(reader, objectType);
}
return retVal;
}
public override bool CanConvert(Type objectType)
{
return false;
}
}
你可以改变这个:
var jsonSingle = "{ '"id'" : '"123'", '"relatedIds'" : '"456'" }";
:
var jsonSingle = "{ '"id'" : '"123'", '"relatedIds'" : [ '"456'" ] }";
…并接受relatedIds
有一个或多个项目,因此应该始终是一个集合。
或者您可以将RelatedIds设置为泛型:
public class MyObject<T>
{
// .... //
public T RelatedIds;
}
你可以这样使用:
var objArray = (MyObject<List<string>>)JsonConvert.DeserializeObject(jsonArray, typeof(MyObject<List<string>>));
var objSingle = (MyObject<object>)JsonConvert.DeserializeObject(jsonSingle, typeof (MyObject<object>));
我个人更喜欢前一个选项,因为简单。
你不能做的一件事是使定义为string
的东西在运行时突然变成List<string>
(实际上也许你可以使用dynamic
,但最好不要去那里…)。这在静态类型语言中是不允许的(尽管在弱类型语言如JS或PHP中是可能的)。
将JsonToken.StartObject
更改为JsonToken.String
。如果在object retVal = new Object();
行上设置一个断点,可以看到在第二次实例化期间,reader.TokenType
是JsonToken.String
。这是你代码的唯一问题。