如何反序列化不同类型的集合?

我有一个看起来像这样的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" } } ] } 

此Feed中有两种类型的事务:具有recipient内部事务,以及具有hshrecipient_address外部事务。

我创建了以下类来容纳这个结构:

UML

因此,我们为所有分页结果( PagedResult )提供了一个基类,其中包含特定的事务实现( TransactionPagedResult )。 这个结果有一个包含0 .. *事务的集合(抽象类Transaction )。 它们不属于Transaction类型,但属于InternalTransactionExternalTransaction类型,它们是Transaction实现。

我的问题是如何让JSON.NET处理这个问题。 我希望JSON.NET查看它正在解析的当前事务是InternalTransaction还是ExternalTransaction ,并将相应类型添加到IEnumerableIEnumerable集合。

我创建了自己的JsonConverter作为属性添加到IEnumerable[JsonConverter(typeof(TransactionCreationConverter))]属性,但这不起作用,我得到以下错误:

附加信息:从JsonReader读取JObject时出错。 当前的JsonReader项不是对象:StartArray。 路径’交易’,第1行,第218位。

我理解这是因为JSON.NET尝试反序列化整个集合,但我希望它逐个反序列化集合中的每个对象。

任何人?

您的问题基本上与此问题重复,解决方案是相同的。 您需要一个JsonConverter来实例化正确的对象。 但是,我看到了一些不同之处。

如果从另一个答案中查看转换器实现,您可以看到它在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(); } else { return transaction.ToObject(); } } public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer) { throw new NotImplementedException(); } } 

假设您的类定义如下:

 class TransactionPagedResult { [JsonProperty(ItemConverterType=typeof(TransactionConverter))] public IEnumerable 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))] 。 我已经编辑了上面的类定义以明确这一点。