2015-12-18 13 views
13

Ho un piccolo problema con il passaggio dell'istanza padre a un costruttore durante la deserializzazione di un oggetto con Newtonsoft.Json.Come passare il parametro al costruttore deserializing json

Supponiamo Ho le seguenti classi

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

e ora ho serailze e che deserializzare l'oggetto a in questo modo:

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

Il problema è che, quando la deserializzazione dell'oggetto, null farò essere passato al costruttore di B. Qualcuno ha già risolto questo problema/problema?

Grazie mille!

+0

Se davvero bisogno di questo, si consiglia di modificare la progettazione. Se non puoi serializzare e poi deserializzare e obiettare, non dovresti usarlo in serializzazione. – CodeCaster

+0

Non ricevo alcun messaggio di errore, il valore passato è solo 'null'. Cambiare l'architettura non è realmente possibile, perché ciò causerebbe un sacco di lavoro di refactoring. – BendEg

+0

Voglio dire se la tua classe si basa su un membro interno, non puoi banalmente deserializzare. La serializzazione di default funziona solo sui membri pubblici. Potresti voler rendere pubblico A o renderlo serializzabile in un altro modo. – CodeCaster

risposta

9

Nella domanda e nei commenti hai detto che la classe B non ha alcuna proprietà pubblica per A. Pertanto, quando serializzi B, non verrà scritto alcun A nel JSON, poiché Json.Net serializza solo le informazioni pubbliche per impostazione predefinita. Pertanto, quando si deserializza, non ci saranno sufficienti informazioni per ricreare B, perché non c'è A nel JSON. Quindi, il primo passaggio sta rendendo visibile il riferimento a A a Json.Net. Se non vuoi renderlo pubblico, va bene, ma dovrai almeno contrassegnare il membro con un attributo [JsonProperty] per consentire a Json.Net di "vederlo".

public class B 
{ 
    [JsonProperty] 
    private A a; 

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

Ora, se si fa quanto sopra vi imbatterete in un secondo problema: la vostra struttura di classe ha un ciclo di riferimento (A ha una lista di B s che si riferiscono ciascuna di nuovo a A), e il serializzatore genera un eccezione di default in questo caso. La soluzione è impostare l'impostazione PreserveReferencesHandling del serializzatore su Objects (il valore predefinito è None). Ciò non solo consentirà al serializzatore di gestire i loop di riferimento durante la serializzazione, ma preserverà anche i riferimenti originali durante la deserializzazione, in modo che tutti gli B si riferiscano alla stessa istanza A. (Questa operazione viene eseguita tramite speciali $id e $ref proprietà che sono scritte in JSON.)

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

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

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

esempio di lavoro: https://dotnetfiddle.net/N0FUID

+0

Funziona perfettamente, proprio quello che stavo cercando! Molte grazie! – BendEg

+0

Nessun problema; felice di poterti aiutare –