2013-08-31 12 views
34

Esiste un modo per ignorare le proprietà get-only utilizzando il serializzatore Json.NET ma senza utilizzare gli attributi JsonIgnore?Esiste un modo per ignorare le proprietà get-only in Json.NET senza utilizzare gli attributi JsonIgnore?

Per esempio, ho una classe con questi ottenere le proprietà:

public Keys Hotkey { get; set; } 

    public Keys KeyCode 
    { 
     get 
     { 
      return Hotkey & Keys.KeyCode; 
     } 
    } 

    public Keys ModifiersKeys 
    { 
     get 
     { 
      return Hotkey & Keys.Modifiers; 
     } 
    } 

    public bool Control 
    { 
     get 
     { 
      return (Hotkey & Keys.Control) == Keys.Control; 
     } 
    } 

    public bool Shift 
    { 
     get 
     { 
      return (Hotkey & Keys.Shift) == Keys.Shift; 
     } 
    } 

    public bool Alt 
    { 
     get 
     { 
      return (Hotkey & Keys.Alt) == Keys.Alt; 
     } 
    } 

    public Modifiers ModifiersEnum 
    { 
     get 
     { 
      Modifiers modifiers = Modifiers.None; 

      if (Alt) modifiers |= Modifiers.Alt; 
      if (Control) modifiers |= Modifiers.Control; 
      if (Shift) modifiers |= Modifiers.Shift; 

      return modifiers; 
     } 
    } 

    public bool IsOnlyModifiers 
    { 
     get 
     { 
      return KeyCode == Keys.ControlKey || KeyCode == Keys.ShiftKey || KeyCode == Keys.Menu; 
     } 
    } 

    public bool IsValidKey 
    { 
     get 
     { 
      return KeyCode != Keys.None && !IsOnlyModifiers; 
     } 
    } 

Devo aggiungere [JsonIgnore] a tutti loro (ho anche molte altre classi), o non c'è modo migliore per ignorare tutto proprietà get-only?

risposta

53

Si può fare questo grazie all'implementazione di un personalizzato IContractResolver e l'utilizzo che durante la serializzazione. Se si sottoclasse il DefaultContractResolver, questo diventa molto facile da fare:

class WritablePropertiesOnlyResolver : DefaultContractResolver 
{ 
    protected override IList<JsonProperty> CreateProperties(Type type, MemberSerialization memberSerialization) 
    { 
     IList<JsonProperty> props = base.CreateProperties(type, memberSerialization); 
     return props.Where(p => p.Writable).ToList(); 
    } 
} 

Ecco un programma di prova che dimostra come usarlo:

using System; 
using System.Collections.Generic; 
using System.Linq; 
using Newtonsoft.Json; 
using Newtonsoft.Json.Serialization; 

class Program 
{ 
    static void Main(string[] args) 
    { 
     Widget w = new Widget { Id = 2, Name = "Joe Schmoe" }; 

     JsonSerializerSettings settings = new JsonSerializerSettings 
     { 
      ContractResolver = new WritablePropertiesOnlyResolver() 
     }; 

     string json = JsonConvert.SerializeObject(w, settings); 

     Console.WriteLine(json); 
    } 
} 

class Widget 
{ 
    public int Id { get; set; } 
    public string Name { get; set; } 
    public string LowerCaseName 
    { 
     get { return (Name != null ? Name.ToLower() : null); } 
    } 
} 

Ecco l'output di cui sopra. Si noti che la proprietà di sola lettura LowerCaseName non è inclusa nell'output.

{"Id":2,"Name":"Joe Schmoe"} 
+0

come ignorare solo le proprietà senza SET? E continua a serializzare quando si ha un set privato come una stringa pubblica Name {get; set privato; }? –

12

Utilizzare la modalità OptIn di JSON.net e sarà necessario solo decorare le proprietà che si desidera serializzare. Questo non è buono come optare automaticamente per tutte le proprietà di sola lettura, ma può farti risparmiare un po 'di lavoro.

[JsonObject(MemberSerialization.OptIn)] 
public class MyClass 
{ 
    [JsonProperty] 
    public string serializedProp { get; set; } 

    public string nonSerializedProp { get; set; } 
} 

udate: aggiunta un'altra possibilità utilizzando la riflessione

Se la soluzione di cui sopra non è ancora abbastanza quello che stai cercando, è possibile utilizzare la riflessione per rendere gli oggetti del dizionario che sarebbe poi essere serializzati. Ovviamente l'esempio seguente funzionerà solo per le classi semplici, quindi sarà necessario aggiungere la ricorsione se le classi contengono altre classi. Questo dovrebbe almeno indirizzarti nella giusta direzione.

La subroutine di mettere il risultato filtrato in un dizionario:

private Dictionary<String, object> ConvertToDictionary(object classToSerialize) 
    { 
     Dictionary<String, object> resultDictionary = new Dictionary<string, object>(); 

     foreach (var propertyInfo in classToSerialize.GetType().GetProperties(BindingFlags.Public | BindingFlags.Instance)) 
     { 
      if (propertyInfo.CanWrite) resultDictionary.Add(propertyInfo.Name, propertyInfo.GetValue(classToSerialize, null)); 
     } 

     return resultDictionary; 
    } 

Un frammento che mostra il suo utilizzo:

SampleClass sampleClass = new SampleClass(); 
sampleClass.Hotkey = Keys.A; 
var toSerialize = ConvertToDictionary(sampleClass); 
String resultText = JsonConvert.SerializeObject(toSerialize); 
7

È possibile utilizzare un sistema di risoluzione del contratto come questo:

public class ExcludeCalculatedResolver : DefaultContractResolver 
{ 
    protected override JsonProperty CreateProperty(MemberInfo member, MemberSerialization memberSerialization) 
    { 
     var property = base.CreateProperty(member, memberSerialization); 
     property.ShouldSerialize = _ => ShouldSerialize(member); 
     return property; 
    } 

    internal static bool ShouldSerialize(MemberInfo memberInfo) 
    { 
     var propertyInfo = memberInfo as PropertyInfo; 
     if (propertyInfo == null) 
     { 
      return false; 
     } 

     if (propertyInfo.SetMethod != null) 
     { 
      return true; 
     } 

     var getMethod = propertyInfo.GetMethod; 
     return Attribute.GetCustomAttribute(getMethod, typeof(CompilerGeneratedAttribute)) != null; 
    } 
} 

Si escluderà proprietà calcolate ma includono C# 6 ottenere solo le proprietà e tutti gli oggetti con un metodo set.

4

Json.net ha la possibilità di serializzare in modo condizionale le proprietà senza un attributo o un risolutore di contratto. Questo è particolarmente utile se non vuoi che il tuo progetto abbia una dipendenza da Json.net.

Come per la Json.net documentation

per serializzare condizionalmente una proprietà, aggiungere un metodo che restituisce booleano con lo stesso nome della proprietà e quindi precedere il nome del metodo con ShouldSerialize.Il risultato del metodo determina se la proprietà è serializzata. Se il metodo restituisce true, la proprietà verrà serializzata, se restituisce false, la proprietà sarà ignorata.

Problemi correlati