[英]Deserializing a mixed list of objects from JSON
我正在使用DataContractJsonSerializer
从外部服务反序列化对象。 在大多数情况下,这对我来说效果很好。 但是,在一种情况下,我需要反序列化 JSON,其中包含一个对象列表,这些对象都继承自同一个基础 class,但该列表中有许多不同类型的对象。
我知道可以通过在序列化程序的构造函数中包含已知类型的列表来轻松完成此操作,但我无法访问生成此 JSON 服务的代码。 我使用的类型将与服务中使用的类型不同(主要是 class 名称和命名空间会不同)。 换句话说,数据被序列化的类与我将用来反序列化它的类不同,即使它们非常相似。
使用 XML DataContractSerializer
,我可以将DataContractResolver
传递给 map 服务类型到我自己的类型,但是DataContractJsonSerializer
没有这样的构造函数。 有没有办法做到这一点? 我能找到的唯一选择是:编写自己的反序列化器,或者使用未经测试且“不应在生产环境中使用”的 Microsoft JsonObject 。
这是一个例子:
[DataContract]
public class Person
{
[DataMember]
public string Name { get; set; }
}
[DataContract]
public class Student : Person
{
[DataMember]
public int StudentId { get; set; }
}
class Program
{
static void Main(string[] args)
{
var jsonStr = "[{\"__type\":\"Student:#UnknownProject\",\"Name\":\"John Smith\",\"StudentId\":1},{\"Name\":\"James Adams\"}]";
using (var stream = new MemoryStream())
{
var writer = new StreamWriter(stream);
writer.Write(jsonStr);
writer.Flush();
stream.Position = 0;
var s = new DataContractJsonSerializer(typeof(List<Person>), new Type[] { typeof(Student), typeof(Person) });
// Crashes on this line with the error below
var personList = (List<Person>)s.ReadObject(stream);
}
}
}
这是上面评论中提到的错误:
Element ':item' contains data from a type that maps to the name
'http://schemas.datacontract.org/2004/07/UnknownProject:Student'. The
deserializer has no knowledge of any type that maps to this name. Consider using
a DataContractResolver or add the type corresponding to 'Student' to the list of
known types - for example, by using the KnownTypeAttribute attribute or by adding
it to the list of known types passed to DataContractSerializer.
我找到了答案。 这很简单。 我只需要更新我的DataContract
属性以指定 map 到源 JSON 中的哪个命名空间(您也可以指定不同的名称),如下所示:
[DataContract(Namespace = "http://schemas.datacontract.org/2004/07/UnknownProject")]
public class Person
{
[DataMember]
public string Name { get; set; }
}
[DataContract(Namespace = "http://schemas.datacontract.org/2004/07/UnknownProject"]
public class Student : Person
{
[DataMember]
public int StudentId { get; set; }
}
该 JsonObject 是 .NET 3.5 的样本。 codeplex 中有一个项目 - http://wcf.codeplex.com - 它具有 JsonValue/JsonObject/JsonArray/JsonPrimitive 类的经过测试的实现,包括源代码和单元测试。 有了它,您可以解析“无类型”JSON。 另一个用得很好的 JSON 框架是 JSON.NET,位于http://json.codeplex.Z4D236D9A504102C50ZAD1504D102C50ZADBZ 。
您可以在序列化之前创建 DTO。
我使用 class 之类的:(伪代码)
class JsonDto
string Content {get;set;}
string Type {get;set;}
ctor(object) => sets Content & Type Properties
static JsonDto FromJson(string) // => Reads a Serialized JsonDto
// and sets Content+Type Properties
string ToJson() // => serializes itself into a json string
object Deserialize() // => deserializes the wrapped object to its saved Type
// using Content+Type properties
T Deserialize<T>() // deserializes the object as above and tries to cast to T
使用JsonDto
,您可以轻松地将任意对象序列化为 JSON 并将它们反序列化为它们的公共基本类型,因为反序列化器将始终知道原始类型并返回 object 引用类型,如果您使用通用Deserialize<T>
方法,它将被强制转换。
一个警告:如果您设置Type
属性,您应该使用该类型的 AssemblyQualifiedName,但是没有版本属性(例如: MyCompany.SomeNamespace.MyType, MyCompany.SomeAssembly
)。 如果您只使用 class Type
的AssemblyQualifiedName
属性,那么如果您的程序集版本发生更改,您最终会出现错误。
我以相同的方式实现了JsonDtoCollection
,它派生自List<JsonDto>
并提供处理对象 collections 的方法。
class JsonDtoCollection : List<JsonDto>
ctor(List<T>) => wraps all items of the list and adds them to itself
static JsonDtoCollection FromJson(string) // => Reads a collection of serialized
// JsonDtos and deserializes them,
// returning a Collection
string ToJson() // => serializes itself into a json string
List<object> Deserialize() // => deserializes the wrapped objects using
// JsonDto.Deserialize
List<T> Deserialize<T>() // deserializes the as above and tries to cast to T
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.