2015-12-18 35 views
13

Mam mały problem z przekazywaniem pewnej instancji nadrzędnej do konstruktora podczas deserializacji obiektu przy pomocy Newtonsoft.Json.Jak przekazać parametr do konstruktora z deserializacją json

Przyjmijmy, mam następujące klasy

public class A 
{ 
    public string Str1 { get; set; } 

    public IList<B> Bs { get; set; } 
} 

public class B 
{ 
    public B(A a) 
    { 
     // a should not be null! 
     Console.WriteLine(a.Str) 
    } 
} 

a teraz serailze i niż deserializowania obiekt a tak:

A a = new A() 
a.Bs = new List<B>() 
a.Bs.Add(new B(a)); 
a.Bs.Add(new B(a)); 
a.Bs.Add(new B(a)); 

var json = JsonConvert.SerializeObject(a); 

// Here i need to call the constructor of B when creating new instances 
var newA = JsonConvert.DeserializeObject<A>(json); 

Problem polega na tym, że podczas deserializacji obiektu, null będzie przekazać do konstruktora B. Czy ktoś wcześniej rozwiązał ten problem/problem?

Dziękuję bardzo!

+0

Jeśli naprawdę potrzebują tego, może chcesz zmienić swój wygląd. Jeśli nie możesz serializować, a następnie deserializować i obiektować, nie powinieneś używać go w serializacji. – CodeCaster

+0

Nie dostaję żadnego komunikatu o błędzie, przekazana wartość to po prostu 'null'. Zmiana projektu nie jest możliwa, ponieważ spowodowałoby to wiele prac związanych z refaktoryzacją. – BendEg

+0

Mam na myśli, jeśli twoja klasa polega na wewnętrznym członku, nie możesz trywializować go. Serializacja domyślnie działa tylko dla członków publicznych. Możesz chcieć uczynić A public lub uczynić go serializowalnym w inny sposób. – CodeCaster

Odpowiedz

9

W swoim pytaniu i komentarzach powiedziałeś, że klasa B nie ma żadnej publicznej właściwości dla A. Tak więc, jeśli serializuje się B, wtedy A nie zostanie zapisany w JSON, ponieważ Json.Net domyślnie serializuje tylko informacje publiczne. Dlatego podczas deserializacji nie będzie wystarczającej ilości informacji do odtworzenia, ponieważ nie ma A w JSON. Tak więc, krok pierwszy powoduje, że B odniesienie do A jest widoczne dla Json.Net. Jeśli nie chcesz, aby było to publiczne, jest to w porządku, ale będziesz musiał przynajmniej zaznaczyć członka atrybutem [JsonProperty], aby umożliwić Json.Net "zobaczenie go".

public class B 
{ 
    [JsonProperty] 
    private A a; 

    public B(A a) 
    { 
     this.a = a; // be sure to set the A member in your constructor 
    } 
} 

Teraz, jeśli nie wyżej was będzie prowadzony do drugiego problemu: strukturę klasa ma pętlę odniesienia (A ma listę B s których każdy odesłać do A), a serializer wygeneruje wyjątek w tym przypadku. Rozwiązaniem jest ustawienie ustawienia serializera na Objects (domyślnie jest to None). Umożliwi to nie tylko serializerowi obsłużenie pętli referencyjnych podczas serializacji, ale także zachowanie oryginalnych odniesień podczas deserializacji, tak że wszystkie s będą odnosić się do tej samej instancji A. (Cel ten realizowany jest poprzez specjalne $id i $ref właściwości, które są zapisywane w formacie JSON.)

JsonSerializerSettings settings = new JsonSerializerSettings 
{ 
    PreserveReferencesHandling = PreserveReferencesHandling.Objects, 
}; 

var json = JsonConvert.SerializeObject(a, settings); 

var newA = JsonConvert.DeserializeObject<A>(json, settings); 

przykład robocza: https://dotnetfiddle.net/N0FUID

+0

Działa doskonale, właśnie tego szukałem! Wielkie dzięki! – BendEg

+0

Bez problemu; cieszę się, że mogłem pomóc. –