2014-06-15 26 views
8

(Ben bu örnek için gerekli olmayan bazı alanları kaldırıldı) şöyle bir yayını, vardır:Koleksiyona farklı türler nasıl seri hale getirilir?

{ 
    "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": "[email protected]" 
     }, 
     "recipient": { 
      "id": "5011f33df8182b142400000a", 
      "name": "User One", 
      "email": "[email protected]" 
     } 
     } 
    }, 
    { 
     "transaction": { 
     "id": "5018f833f8182b129c00002e", 
     "created_at": "2012-08-01T02:36:43-07:00", 
     "hsh": "9d6a7d1112c3db9de5315b421a5153d71413f5f752aff75bf504b77df4e646a3", 
     "sender": { 
      "id": "5011f33df8182b142400000e", 
      "name": "User Two", 
      "email": "[email protected]" 
     }, 
     "recipient_address": "37muSN5ZrukVTvyVh3mT5Zc5ew9L9CBare" 
     } 
    } 
] 
} 

işlemler iki tür Bu feed'de vardır: recipient sahip dahili işlemleri, ve hsh ve recipient_address olan harici işlemler.

UML

yüzden işlemler için belirli bir uygulaması ( TransactionPagedResult) ile tüm disk belleği sonuçları ( PagedResult) için bir temel sınıf vardır:

bu yapıyı karşılamak için aşağıdaki sınıflar yarattı. Bu sonuç 0 .. * işlemlerini içeren bir koleksiyona sahiptir (soyut sınıf Transaction). Bunlar, Transaction türünde değil, veya ExternalTransaction türlerinde değil, Transaction numaralı uygulamalardır.

Sorum, JSON.NET'in buna nasıl izin verebildiğim sorusudur. JSON.NET'in ayrıştırmakta olan geçerli işlemin InternalTransaction veya ExternalTransaction olup olmadığını görmek ve TransactionPagedResult içinde IEnumerable<Transaction> koleksiyonuna ilgili türü ekleyin.

ben [JsonConverter(typeof(TransactionCreationConverter))] özniteliği ile IEnumerable<Transaction> bir özellik olarak eklendi benim kendi JsonConverter oluşturuldu, ancak bu aşağıdaki hatayı alıyorum, işe yaramadı:

Additional information: Error reading JObject from JsonReader. Current JsonReader item is not an object: StartArray. Path 'transactions', line 1, position 218.

bu JSON çünkü anlıyoruz. NET, tüm koleksiyonu seri hale getirmeye çalışır, ancak koleksiyondaki her bir nesneyi birer birer tekrar serilemek istiyorum.

Herkes?

+0

iyi bir gönderi, ama tam olarak ne demek istediğimin bilgisini ekleyebilir misiniz ..."Ama bu işe yaramadı" mesajın en sonunda? –

+0

Evet, bunu eklemedim çünkü yazının çok uzun olmasını istemedim. JsonReader öğesinin bir nesne değil, bir dizi (yani, IEnumerable koleksiyonuna özniteliği yerleştirdiğim için doğru olan) bir hata olduğunu anladım. JsonConverter'ın IEnumerable'daki her bir öğeye bakmasını istiyorum. –

+0

@Jack Yanlış iş parçacığına bağlı olduğunu mu düşünüyorsun? –

cevap

6

Sorunuz, aslında bir this one kopyasıdır ve çözüm aynıdır. Doğru nesneyi başlatmak için JsonConverter'a ihtiyacınız var. Ancak, gördüğüm birkaç farklılık var.

Dönüştürücü uygulamasına other answer'dan bakarsanız, örneklenecek türü belirlemek için JSON'da bir boole bayrağı aradığını görürsünüz. Sizin durumunuzda, böyle bir bayrak yoktur, bu yüzden bu kararlılığı sağlamak için bir alanın varlığını veya yokluğunu kullanmanız gerekir. Ayrıca, JSON'daki işlem listeniz aslında 'un işlemlerini içeren nesnelerin bir listesidir, bu nedenle dönüştürücünün de bunun hesaba katılması gerekir. Ayrıca

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; } 
} 

, sorunuzun son bölümünü cevap:

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(); 
    } 
} 

dersleriniz böyle tanımlanır varsayarak: Bu değişikliklerle birlikte

, senin dönüştürücü bu gibi görünmelidir Listenizi [JsonConverter] özniteliği ile dekore ederseniz, dönüştürücünün tüm listeyi ele alması beklenir. Tek tek öğeleri işlemek için, listede [JsonProperty(ItemConverterType=typeof(TransactionConverter))] kullanmanız gerekir. Bunu açıklamak için yukarıdaki sınıf tanımlarını düzenledim.

+0

Harika! Bu hile yapar :) Örnek ve açıklama için çok teşekkürler! :) –

+0

Sorun yok; yardımcı olduğuma sevindim. –

İlgili konular