Json.net türetilmiş türleri seri hale getirme / seri durumdan çıkarma


99

json.net (newtonsoft) Dokümantasyonlara
bakıyorum ama bununla ilgili hiçbir şey veya bunu yapmanın en iyi yolunu bulamıyorum.

public class Base
{
    public string Name;
}
public class Derived : Base
{
    public string Something;
}

JsonConvert.Deserialize<List<Base>>(text);

Artık serileştirilmiş listede Türetilmiş nesnelerim var. Listenin serisini nasıl kaldırabilirim ve türetilmiş türleri nasıl geri alabilirim?


Miras böyle yürümez. JsonConvert.Deserialize <Derived> (metin) belirtebilirsiniz; Ad alanını dahil etmek için. Türetilmiş Bir Temel Olduğundan (tam tersi değil), Base Derived'in tanımı hakkında hiçbir şey bilmiyor.
M.Babcock

Üzgünüm, biraz açıklığa kavuşturuldu. Sorun şu ki, hem temel hem de türetilmiş nesneleri içeren bir listem var. Bu yüzden, newtonsoft'a türetilen öğelerin seri durumunun nasıl kaldırılacağını nasıl söyleyeceğimi bulmam gerekiyor.
Will

Bunu sen çözdün. Bende de aynı sorun var
Luis Carlos Chavarría

Yanıtlar:


47

Türü kendi içinde depoluyorsanız text(bu senaryoda olması gerektiği gibi) JsonSerializerSettings,.

Bkz: Newtonsoft JSON.NET ile JSON'u IEnumerable <BaseType> olarak seri durumdan çıkarma

Yine de dikkatli olun. Başka bir şey kullanmak TypeNameHandling = TypeNameHandling.Nonekendinizi bir güvenlik açığına açabilir .


24
Ayrıca kullanabilirsiniz TypeNameHandling = TypeNameHandling.Auto- bu, $typeYALNIZCA bildirilen türün (ie Base) örnek türüyle (ie Derived) eşleşmediği durumlar için bir özellik ekler . Bu şekilde, JSON'nuzu o kadar şişirmez TypeNameHandling.All.
AJ Richardson

JSON '..., ...' içinde belirtilen türden hata çözme hatası almaya devam ediyorum. Yol '$ type', satır 1, konum 82. Herhangi bir fikriniz var mı?
briba

3
Bunu herkese açık bir uç noktada kullanırken,
gjvdkamp

1
@gjvdkamp JEEZ bunun için teşekkürler, bunu bilmiyordum. Yazıma eklenecek.
kamranicus

97

Tip Adı İşlemeyi etkinleştirmeniz ve bunu (de) serileştiriciye bir ayar parametresi olarak iletmeniz gerekir.

Base object1 = new Base() { Name = "Object1" };
Derived object2 = new Derived() { Something = "Some other thing" };
List<Base> inheritanceList = new List<Base>() { object1, object2 };

JsonSerializerSettings settings = new JsonSerializerSettings { TypeNameHandling = TypeNameHandling.All };
string Serialized = JsonConvert.SerializeObject(inheritanceList, settings);
List<Base> deserializedList = JsonConvert.DeserializeObject<List<Base>>(Serialized, settings);

Bu, türetilmiş sınıfların doğru serileştirilmesiyle sonuçlanacaktır. Bunun bir dezavantajı, kullandığınız tüm nesneleri adlandırmasıdır, bu nedenle nesneleri koyduğunuz listeyi adlandıracaktır.


31
+1. SerializeObject ve DeserializeObject için aynı ayarları kullanmanız gerektiğini öğrenene kadar 30 dakika boyunca googling yapıyordum. Seri durumdan çıkarılırken varsa, $ type'ı örtük olarak kullanacağını varsaydım, aptal ben.
Erti-Chris Eelmaa

24
TypeNameHandling.Autobunu da yapacak ve daha hoş çünkü alan / özellik türüyle eşleştiğinde örnek türü adını yazmıyor, çoğu alan / özellik için bu genellikle geçerli.
Roman Starkov

2
Bu, başka bir çözüm / proje üzerinde serileştirme gerçekleştirildiğinde çalışmaz. Serileştirmede, Çözümün adı şu tür olarak gömülüdür: "SOLUTIONNAME.Models.Model". Diğer çözümdeki serileştirme kaldırıldığında, "JsonSerializationException: 'SOLUTIONNAME' derlemesi yüklenemedi.
Jebathon

19

Soru çok popüler olduğundan, type özelliği adını ve değerini kontrol etmek istiyorsanız ne yapmanız gerektiğini eklemek faydalı olabilir.

Uzun yol, JsonConvertertype özelliğini manuel olarak kontrol edip ayarlayarak (de) serileştirmeyi işlemek için özel s yazmaktır .

Daha basit bir yol, tüm standart metinleri öznitelikler aracılığıyla işleyen JsonSubTypes kullanmaktır :

[JsonConverter(typeof(JsonSubtypes), "Sound")]
[JsonSubtypes.KnownSubType(typeof(Dog), "Bark")]
[JsonSubtypes.KnownSubType(typeof(Cat), "Meow")]
public class Animal
{
    public virtual string Sound { get; }
    public string Color { get; set; }
}

public class Dog : Animal
{
    public override string Sound { get; } = "Bark";
    public string Breed { get; set; }
}

public class Cat : Animal
{
    public override string Sound { get; } = "Meow";
    public bool Declawed { get; set; }
}

4
İhtiyacı anlıyorum, ancak temel sınıfı tüm "Bilinen Alt Tür" lerden haberdar etme zorunluluğunun hayranı değilim ...
Matt Knowles

2
Belgelere bakarsanız başka seçenekler de var. Ben sadece daha çok sevdiğim örneği verdim.
rzippo

1
Bu, hizmetinizin serileştirmeden sonra rastgele türler yüklemesine maruz kalmayan daha güvenli bir yaklaşımdır.
David Burg

3

Bu JsonKnownTypes'i kullanın, kullanıma çok benzer, sadece json'a ayırıcı ekler:

[JsonConverter(typeof(JsonKnownTypeConverter<BaseClass>))]
[JsonKnownType(typeof(Base), "base")]
[JsonKnownType(typeof(Derived), "derived")]
public class Base
{
    public string Name;
}
public class Derived : Base
{
    public string Something;
}

Şimdi nesneyi json içinde serileştirdiğinizde, "$type"ile "base"ve "derived"değer eklenecek ve seri durumdan çıkarmak için kullanılacaktır.

Serileştirilmiş liste örneği:

[
    {"Name":"some name", "$type":"base"},
    {"Name":"some name", "Something":"something", "$type":"derived"}
]
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.