[英]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.