2015-02-23 4 views
8

Ich verwende Newtonsoft's JsonSerializer, um einige Klassen zu serialisieren.Wie kann ich ein Attribut in einer abgeleiteten Klasse "un-JsonIgnore"?

Als ich ein Feld meiner Klasse in der Serialisierung verzichten wollte, erklärte ich es wie folgt:

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

Das funktionierte, aber ich bin jetzt ein neues Problem: In einer abgeleiteten Klasse I möchte, dass dieses Feld angezeigt wird (und tun Sie dies nur in dieser spezifischen abgeleiteten Klasse).

Ich habe in der Dokumentation und im Internet nach einer Möglichkeit gesucht, diese Einstellung in untergeordneten Klassen zu überschreiben (ich denke, ich brauche etwas wie [JsonStopIgnore], aber ich konnte nichts in der Nähe finden).


  • Gibt es für mich eine Möglichkeit, JsonSerializer zu zwingen, wieder dieses Attribut zu holen?
  • Ist es möglich, ein Attribut explizit als [JsonIgnore], aber nur in der Basisklasse zu markieren?

Antwort

7

Sie können dies tun, indem Sie eine benutzerdefinierte DefaultContractResolver Erstellen und Überschreiben seine CreateProperty Methode.

Zum Beispiel gegeben eine Foo Basis und eine abgeleitete Bar:

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

public class Bar : Foo 
{ } 

Sie können folgende Vertrags Resolver erstellen:

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

Diese alle Eigenschaften Ignored = false gesetzt wird, und dann analysieren durch das gegebene Prädikat:

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

Was in unserem Fall bedeutet "Sie sollten nur serialisieren, wenn sie nicht vom Typ Foo sind" (da Foo der DeclaryingType ist).

Und dann, wenn Sie deserialisieren möchten, können Sie eine Instanz des Vertrages Resolver JsonSerializerSettings passieren:

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

Vielen Dank für diese Erklärung zu ContractResolvers! Wenn ich keine leichtere Lösung finden kann, werde ich diesen Weg gehen, der zumindest eine Anpassung erlaubt. – PLNech

+1

@PLNech Sicher Sache. Dies ist definitiv die "schwerste" Lösung, aber ich nehme an, dass es auch die "richtige" Art ist, es mit Json.NET zu handhaben. –

+1

Und ich bin dankbar, dass ich jetzt einen Verweis auf den "richtigen" Weg habe, sollte ich mich nicht in der Lage finden, einen "faulen" zu verwenden: P – PLNech

3

Sie können wahrscheinlich ParentId in der abgeleiteten Klasse einfach überschreiben.

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

Beachten Sie jedoch, dass jede Umwandlung in die zugrunde liegende Klasse Zugriff auf die ausgeblendete Eigenschaft gewährt! –

+1

@AndreasNiedermair Ja. Aber ich denke, dass sowohl während der Serialisierung als auch der Deserialisierung mit Newtonsoft JSonSerializer es funktionieren sollte. Für den verbleibenden Code ist es in Ordnung, wenn diese Eigenschaft umgangen wird. – xanatos

9

Die einzige Möglichkeit, das Verhalten des [JsonIgnore] Attribut auf „Override“ ist ein Vertrag Resolver zu verwenden, wie @ Yuval Itzchakov in seiner Antwort schön erklärt.

Allerdings gibt es eine weitere mögliche Lösung, die für Sie arbeiten könnte: stattdessen ein [JsonIgnore] Attribut zu verwenden, können Sie eine ShouldSerializeParentId() Methode in Klassen implementieren zu steuern, ob die ParentId Eigenschaft serialisiert wird. Geben Sie in der Basisklasse diese Methode false zurück; Überschreiben Sie dann die Methode in der abgeleiteten Klasse, um true zurückzugeben. (Diese Funktion ist in Json.Net als conditional property serialization bekannt.

)
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

Vielen Dank für diese Erklärung eines Mechanismus, von dem ich nichts wusste! Obwohl ein bisschen schwer, kann dies eine einfachere Lösung als die Verwendung eines benutzerdefinierten Vertrags Resolver, um das gleiche Ergebnis zu erreichen :) – PLNech

+1

Kein Problem; froh, dass ich Helfen kann. –

2

Ich löste das gleiche Problem mit dem neuen Schlüsselwort auf der Eigenschaft der abgeleiteten Klasse.

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

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

Danke, es ist gut zu wissen, dass dies auch möglich ist. – PLNech

+0

Ich habe keine Ahnung, warum das funktioniert, aber es tut. Ich benutze mongoDb, um Objekte danach zu speichern, und das wirft jetzt Mapping-Fehler auf mich ... – bonitzenator

1

Ich löste das gleiche Problem mit einem Geister Eigenschaft:

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

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

Wenn ich ziemlich immer versteckt diese Eigenschaft zeigen wollen, ich bevölkern es, ein anderes Mal ist es null:

Foos.ForEach(x => x.FooParent = ParentId); 
Verwandte Themen