2015-02-23 10 views
8

Sto usando Newtonsoft's JsonSerializer per serializzare alcune classi.Come posso "un-JsonIgnore" un attributo in una classe derivata?

Come ho voluto omettere un campo della mia classe nel processo di serializzazione, ho dichiarato come segue:

[JsonIgnore] 
public int ParentId { get; set; } 

Questo ha funzionato, ma ora sto affrontando un nuovo problema: in una classe derivata, io vorrebbe che questo campo appaia (e lo faccia solo in questa specifica classe derivata).

Ho cercato nella documentazione e su Internet un modo per sovrascrivere questa impostazione nelle classi figlie (suppongo di aver bisogno di qualcosa come [JsonStopIgnore], ma non ho trovato nulla di simile).


  • C'è un modo per me di forzare JsonSerializer a riprendere questo attributo?
  • E 'possibile contrassegnare in modo esplicito un attributo come [JsonIgnore], ma solo nella classe di base?

risposta

7

È possibile farlo attraverso la creazione di un custom DefaultContractResolver e ridefinendo il suo metodo CreateProperty.

Ad esempio, dato una base Foo e un derivato Bar:

public class Foo 
{ 
    [JsonIgnore] 
    public string Name { get; set; } 
    public int Age { get; set; } 
} 

public class Bar : Foo 
{ } 

È possibile creare il seguente contratto resolver:

public class MyTypeContractResolver<T> : DefaultContractResolver 
{ 
    protected override JsonProperty CreateProperty(MemberInfo member, 
                MemberSerialization 
                 memberSerialization) 
    { 
     var property = base.CreateProperty(member, memberSerialization); 

     property.Ignored = false; 
     property.ShouldSerialize = propInstance => property.DeclaringType != typeof (T); 
     return property; 
    } 
} 

Questo imposterà tutti gli oggetti da Ignored = false, e poi analizzarle secondo il predicato specificato:

propInstance => property.DeclaringType != typeof (T); 

Che nel nostro caso significa "si dovrebbe serializzare solo se non sono di tipo Foo" (poiché Foo è il DeclaryingType).

E poi, quando si vuole deserializzare, si passa un'istanza del resolver contratto per JsonSerializerSettings:

var bar = new Bar(); 
var result = JsonConvert.SerializeObject(bar, 
    new JsonSerializerSettings {ContractResolver = new MyTypeContractResolver<Bar>()}); 
+0

Grazie per questa spiegazione su ContractResolvers! Se non riesco a trovare una soluzione più leggera, andrò in questo modo che, almeno, consente la personalizzazione della torcia. – PLNech

+1

@PLNech Sicuro. Questa è sicuramente la soluzione "più pesante", ma presumo che sia anche il modo "corretto" di gestirlo con Json.NET. –

+1

E sono grato che ora ho un riferimento al modo "corretto", dovrei trovarmi incapace di usare uno "pigro": P – PLNech

3

Probabilmente è possibile semplicemente sovrascrivere ParentId nella classe derivata.

public new int ParentId 
{ 
    get { return base.ParentId; } 
    set { base.ParentId = value; } 
} 
+1

ma attenzione, qualsiasi cast alla classe sottostante darà accesso alla proprietà nascosta! –

+1

@AndreasNiedermair Sì. Ma penso che sia durante la serializzazione che la deserializzazione con Newtonsoft JSonSerializer dovrebbe funzionare. Per il codice rimanente va bene se questa proprietà viene ignorata. – xanatos

9

L'unico modo per "override" il comportamento dell'attributo [JsonIgnore] è quello di utilizzare un sistema di risoluzione del contratto, come @ Yuval Itzchakov ha ben spiegato nella sua risposta.

Tuttavia, v'è un'altra soluzione possibile che potrebbe funzionare per voi: invece di utilizzare un attributo [JsonIgnore], si potrebbe implementare un metodo ShouldSerializeParentId() nelle classi per controllare se la proprietà ParentId viene serializzato. Nella classe base, rendere questo metodo restituito false; quindi, eseguire l'override del metodo nella classe derivata per restituire true. (Questa funzionalità è nota come conditional property serialization in Json.Net.)

public class Base 
{ 
    public int Id { get; set; } 
    public int ParentId { get; set; } 

    public virtual bool ShouldSerializeParentId() 
    { 
     return false; 
    } 
} 

public class Derived : Base 
{ 
    public override bool ShouldSerializeParentId() 
    { 
     return true; 
    } 
} 

Fiddle: https://dotnetfiddle.net/65sCSz

+0

Grazie per questa spiegazione di un meccanismo di cui non sapevo nulla! Anche se un po 'pesante, questa potrebbe essere una soluzione più semplice rispetto all'utilizzo di un resolver di contratto personalizzato per ottenere lo stesso risultato :) – PLNech

+1

Nessun problema; felice di aiutare. –

2

ho risolto lo stesso problema utilizzando la nuova parola chiave sulla proprietà della classe derivata.

public class Foo 
{ 
    [JsonIgnore] 
    public int ParentId { get; set; } 
} 

public class Bar: Foo 
{ 
    [JsonProperty("ParentId")] 
    public new int ParentId { get; set; } 
} 
+0

Grazie, è bello sapere che è possibile anche questo. – PLNech

+0

Non ho idea del perché funzioni, ma lo fa. Sto usando mongoDb per salvare gli oggetti in seguito e questo genera errori di mappatura ora ... – bonitzenator

1

ho risolto lo stesso problema con una proprietà fantasma:

public class Foo 
{ 
    [JsonIgnore] 
    public int ParentId { get; set; } 

    [NotMapped] 
    public int FooParent { get; set; } 
} 

Quando voglio mostrare questa proprietà quasi sempre nascosta, io popolo che, altre volte è nullo:

Foos.ForEach(x => x.FooParent = ParentId); 
Problemi correlati