我有一个看起来像这样的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
的内部交易,以及具有hsh
和recipient_address
的外部交易。
我创建了以下类来容纳这种结构:
因此,我们为所有分页结果(PagedResult
)提供了一个基类,其中包含特定的事务实现(TransactionPagedResult
)。此结果具有包含0 .. *事务(抽象类Transaction
)的集合。它们不属于Transaction
类型,但类型为InternalTransaction
或ExternalTransaction
,它们是Transaction
的实现。
我的问题是如何让JSON.NET处理这个问题。我希望JSON.NET查看它正在解析的当前事务是InternalTransaction
还是ExternalTransaction
,并将相应类型添加到IEnumerable<Transaction>
中的TransactionPagedResult
集合。
我创建了自己的JsonConverter,我将其作为属性添加到具有IEnumerable<Transaction>
属性的[JsonConverter(typeof(TransactionCreationConverter))]
,但这不起作用,我收到以下错误:
其他信息:从JsonReader读取JObject时出错。当前 JsonReader项不是对象:StartArray。路径'交易', 第1行,第218位。
我理解这是因为JSON.NET尝试反序列化整个集合,但我希望它逐个反序列化集合中的每个对象。
任何?
答案 0 :(得分:6)
您的问题基本上是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))]
。我已经编辑了上面的类定义,以明确这一点。