如何反序列化收集不同类型的? [英] How to deserialize collection with different types?
问题描述
我有一个JSON提要看起来像这样(我删除了一些字段是没有必要在这个例子中):
I have a JSON feed that looks like this (I removed some fields that aren't necessary for this example):
{
"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"
}
}
]
}
有两种类型的这种饲料交易:有一个收件人
内部交易和外部交易有一个 HSH
和 RECIPIENT_ADDRESS
。
There are two types of transactions in this feed: internal transactions that have a recipient
, and external transactions that have a hsh
and recipient_address
.
我创建了下面的类,以适应这种结构:
I created the following classes to accomodate this structure:
因此,我们必须对所有的基类分页的结果( PagedResult
)与特定实现交易(TransactionPagedResult <$ C C $> )。该结果包含0 .. *交易集合(抽象类交易
)。他们的类型并不交易
不过,但类型的 InternalTransaction
或 ExternalTransaction
这是交易
的实现。
So we have a base class for all paged results (PagedResult
) with a specific implementation for transactions (TransactionPagedResult
). This result has a collection containing 0..* transactions (abstract class Transaction
). They're not of the type Transaction
though, but of type InternalTransaction
or ExternalTransaction
which are implementations of Transaction
.
我的问题是我怎么可以让JSON.NET处理这个问题。我想JSON.NET看到当前事务它的解析是否是 InternalTransaction
或 ExternalTransaction
,并根据该加键入到的IEnumerable&LT;交易&GT;
集合 TransactionPagedResult
My question is how I can let JSON.NET handle this. I want JSON.NET to see whether the current transaction it's parsing is an InternalTransaction
or an ExternalTransaction
, and add the according type to the IEnumerable<Transaction>
collection in TransactionPagedResult
.
我创造了我添加为一个属性,我自己JsonConverter的的IEnumerable&LT;交易&GT;
与 [JsonConverter(typeof运算(TransactionCreationConverter))]
属性,但这并没有工作,我得到以下错误:
I created my own JsonConverter that I added as a property to the IEnumerable<Transaction>
with the [JsonConverter(typeof(TransactionCreationConverter))]
attribute, but this didn't work, I get the following error:
更多信息:错误从JsonReader阅读JObject。当前 JsonReader产品不是一个对象:StartArray。路径'交易', 1号线,位置218。
Additional information: Error reading JObject from JsonReader. Current JsonReader item is not an object: StartArray. Path 'transactions', line 1, position 218.
据我所知,这是因为JSON.NET试图反序列化整个集合,但我想它由一个反序列化集合中的一个内部的每个对象。
I understand this is because JSON.NET tries to deserialize the whole collection, but I want it to deserialize each object inside the collection one by one.
有人吗?
推荐答案
您的问题本质上是这个的副本,并将该溶液是相同的。你需要一个 JsonConverter
实例化正确的对象。不过,也有几个,我看到的差异。
Your question is essentially a duplicate of this one, and the solution is the same. You need a JsonConverter
to instantiate the correct object. However, there are a couple of differences that I see.
如果你从对方回答转换器实现,你可以看到它寻找一个布尔标志JSON的确定类型来实例化。在你的情况下,有没有这样的标志,所以你需要使用一个字段的存在与否来做出判断。此外,您在JSON交易的名单实际上是的包含的交易对象的列表,所以转换器需要考虑到这一点。
If you look at the converter implementation from the other answer, you can see that it looks for a boolean flag in the JSON to determine the type to instantiate. In your case, there is not such a flag, so you'd need to use the existence or absence of a field to make this determination. Also, your list of transactions in the JSON is actually a list of objects that contain transactions, so the converter needs to account for that as well.
通过这些改变,你的转换器应该是这个样子:
With these changes, your converter should look something like this:
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();
}
}
假设你的类定义是这样的:
assuming that your classes are defined like this:
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))]
的列表,而不是上。我已经编辑上面的类定义,以明确这一点。
Also, to answer the last part of your question, if you decorate your list with a [JsonConverter]
attribute, the converter is expected to handle the entire list. To handle the individual items, you need to use [JsonProperty(ItemConverterType=typeof(TransactionConverter))]
on the list instead. I've edited the class definitions above to make this clear.
这篇关于如何反序列化收集不同类型的?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!