2013-08-31 11 views
34

Czy można zignorować właściwości tylko do pobrania za pomocą serializera Json.NET, ale bez używania atrybutów JsonIgnore?Czy istnieje sposób ignorowania właściwości tylko do pobrania w Json.NET bez używania atrybutów JsonIgnore?

Na przykład, mam klasy z nich uzyskać właściwości:

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

Czy muszę dodawać [JsonIgnore] do wszystkich z nich (mam również wiele innych klas), czy istnieje lepszy sposób, aby ignorować wszystkie właściwości get-only?

Odpowiedz

53

Można to zrobić poprzez wdrożenie niestandardowych IContractResolver i stosując że podczas serializacji. Jeśli podklasy DefaultContractResolver, to staje się bardzo łatwe do zrobienia:

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

Oto program testowy pokazujący, jak z niego korzystać:

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

Tutaj jest wyjście z powyższych. Zauważ, że właściwość tylko do odczytu LowerCaseName nie jest zawarta w danych wyjściowych.

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

jak zignorować tylko właściwości bez SET? I nadal serializuje, gdy zestaw prywatny, taki jak public string Name {get; prywatny zestaw; }? –

12

Użyj trybu OptIn w JSON.net, a będziesz musiał tylko ozdobić właściwości, które chcesz serializować. To nie jest tak dobre, jak automatyczne wyłączanie wszystkich właściwości tylko do odczytu, ale może to zaoszczędzić trochę pracy.

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

    public string nonSerializedProp { get; set; } 
} 

Udate: Dodano kolejną możliwość przy użyciu odbicia

Jeśli powyższe rozwiązanie nie jest jeszcze całkiem to, czego szukasz, możesz użyć refleksji do słownika obiektów, które byłyby następnie szeregowane. Oczywiście poniższy przykład działa tylko dla prostych klas, więc musisz dodać rekursję, jeśli twoje klasy zawierają inne klasy. To powinno przynajmniej wskazać ci właściwy kierunek.

Podprogram umieścić przefiltrowaną wynik w słowniku:

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

fragment pokazujący jego zastosowanie:

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

Można użyć rozpoznawania nazw kontrakt tak:

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

To wykluczy obliczonych właściwości ale to C# 6 dostać tylko właściwości i wszystkie właściwości z metodą przedstawioną.

4

Json.net ma możliwość warunkowego serializowania właściwości bez atrybutu lub resolwera umowy. Jest to szczególnie przydatne, jeśli nie chcesz, aby twój projekt był zależny od Json.net.

Jak na Json.net documentation

warunkowo serializacji właściwość, dodać metodę, która zwraca wartość logiczną z taką samą nazwę jak nieruchomości, a następnie poprzedzić nazwę metody z ShouldSerialize.Wynik tej metody określa, czy właściwość jest serializowana. Jeśli metoda zwróci wartość true, właściwość zostanie przekształcona do postaci szeregowej, jeśli zwróci wartość false, wówczas właściwość zostanie pomijana: właściwość .

Powiązane problemy