如何反序列化不同类型的集合?
Posted
技术标签:
【中文标题】如何反序列化不同类型的集合?【英文标题】:How to deserialize collection with different types? 【发布时间】:2014-08-05 10:54:16 【问题描述】:我有一个如下所示的 JSON 提要(我删除了本示例不需要的一些字段):
"total_count": 2,
"num_pages": 1,
"current_page": 1,
"balance":
"amount": "0.00001199",
"currency": "BTC"
,
"transactions": [
"transaction":
"id": "5018f833f8182b129c00002f",
"created_at": "2012-08-01T02:34:43-07:00",
"sender":
"id": "5011f33df8182b142400000e",
"name": "User Two",
"email": "user2@example.com"
,
"recipient":
"id": "5011f33df8182b142400000a",
"name": "User One",
"email": "user1@example.com"
,
"transaction":
"id": "5018f833f8182b129c00002e",
"created_at": "2012-08-01T02:36:43-07:00",
"hsh": "9d6a7d1112c3db9de5315b421a5153d71413f5f752aff75bf504b77df4e646a3",
"sender":
"id": "5011f33df8182b142400000e",
"name": "User Two",
"email": "user2@example.com"
,
"recipient_address": "37muSN5ZrukVTvyVh3mT5Zc5ew9L9CBare"
]
此提要中有两种类型的交易:具有recipient
的内部交易,以及具有hsh
和recipient_address
的外部交易。
我创建了以下类来适应这种结构:
因此,我们为所有分页结果 (PagedResult
) 提供了一个基类,并为事务 (TransactionPagedResult
) 提供了特定实现。这个结果有一个包含 0..* 事务的集合(抽象类Transaction
)。它们不是Transaction
类型,而是InternalTransaction
或ExternalTransaction
类型,它们是Transaction
的实现。
我的问题是如何让 JSON.NET 处理这个问题。我希望 JSON.NET 查看它正在解析的当前事务是 InternalTransaction
还是 ExternalTransaction
,并将相应的类型添加到 TransactionPagedResult
中的 IEnumerable<Transaction>
集合中。
我创建了自己的 JsonConverter,并使用 [JsonConverter(typeof(TransactionCreationConverter))]
属性将其作为属性添加到 IEnumerable<Transaction>
,但这不起作用,我收到以下错误:
附加信息:从 JsonReader 读取 JObject 时出错。当前的 JsonReader 项不是对象:StartArray。路径“交易”, 第 1 行,位置 218。
我理解这是因为 JSON.NET 试图反序列化整个集合,但我希望它一个一个地反序列化集合中的每个对象。
有人吗?
【问题讨论】:
到目前为止的帖子不错,但是您能否在帖子的最后添加您所说的...“但这不起作用”的确切含义? 是的,我没有添加,因为我不希望帖子变得太长。我收到一个错误,指出 JsonReader 项不是对象而是数组(这是正确的,因为我将属性放在 IEnumerable 集合上)。我希望 JsonConverter 查看 IEnumerable 中的每个项目,它们都是对象。 @Jack 我认为你链接到了错误的线程? 这有帮助吗? ***.com/questions/7699972/… 编辑:固定链接 Deserializing polymorphic json classes without type information using json.net的可能重复 【参考方案1】:你的问题本质上是this one的重复,解决方法是一样的。您需要一个 JsonConverter
来实例化正确的对象。但是,我看到了一些不同之处。
如果您查看 other answer 中的转换器实现,您可以看到它在 JSON 中查找布尔标志来确定要实例化的类型。在您的情况下,没有这样的标志,因此您需要使用字段的存在或不存在来做出此决定。此外,JSON 中的交易列表实际上是 包含 交易的对象列表,因此转换器也需要考虑这一点。
通过这些更改,您的转换器应如下所示:
public class TransactionConverter : JsonConverter
public override bool CanConvert(Type objectType)
return typeof(Transaction).IsAssignableFrom(objectType);
public override object ReadJson(JsonReader reader,
Type objectType, object existingValue, JsonSerializer serializer)
JToken transaction = JToken.Load(reader)["transaction"];
if (transaction["recipient"] != null)
return transaction.ToObject<InternalTransaction>();
else
return transaction.ToObject<ExternalTransaction>();
public override void WriteJson(JsonWriter writer,
object value, JsonSerializer serializer)
throw new NotImplementedException();
假设你的类是这样定义的:
class TransactionPagedResult
[JsonProperty(ItemConverterType=typeof(TransactionConverter))]
public IEnumerable<Transaction> Transactions get; set;
class Transaction
public string Id get; set;
[JsonProperty("created_at")]
public DateTime CreatedAt get; set;
class InternalTransaction : Transaction
public User Recipient get; set;
class ExternalTransaction : Transaction
public string Hsh get; set;
[JsonProperty("recipient_address")]
public string RecipientAddress get; set;
class User
public string Id get; set;
public string Name get; set;
public string Email get; set;
另外,为了回答你问题的最后一部分,如果你用[JsonConverter]
属性装饰你的列表,转换器应该会处理整个列表。要处理单个项目,您需要使用列表中的[JsonProperty(ItemConverterType=typeof(TransactionConverter))]
。我已经编辑了上面的类定义以明确这一点。
【讨论】:
太棒了!这可以解决问题:) 非常感谢您的示例和解释! :) 没问题;很高兴我能帮上忙。以上是关于如何反序列化不同类型的集合?的主要内容,如果未能解决你的问题,请参考以下文章