2013-08-31 44 views
34

有沒有辦法忽略使用Json.NET序列化器但不使用JsonIgnore屬性的只能獲取屬性?有沒有辦法在不使用JsonIgnore屬性的情況下忽略Json.NET中的只讀屬性?

例如,我有這些類獲得的屬性:

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

我是否需要添加[JsonIgnore]到所有的人(我也有許多其他類),或者有更好的辦法忽略所有隻獲取屬性?

回答

53

您可以通過實現自定義IContractResolver並使用該序列化過程中做到這一點。如果子類DefaultContractResolver,這變得很容易做到:

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

這是一個測試程序,演示如何使用它:

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

這裏是上面的輸出。請注意,輸出中不包含只讀屬性LowerCaseName

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

如何忽略沒有SET的屬性?並且仍然序列化時像public string Name {get;私人設置; }? –

12

使用JSON.net的OptIn模式,你只需要修飾你想要序列化的屬性。這不如自動選擇所有隻讀屬性,但它可以爲您節省一些工作。

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

    public string nonSerializedProp { get; set; } 
} 

UDATE:增加使用反射

另一種可能性如果上述解決方案仍然是不是你要找相當的內容,你可以使用反射,使這將隨後被序列化字典對象。當然下面的例子只適用於簡單的類,所以如果你的類包含其他類,你將需要添加遞歸。這至少應該指向正確的方向。

子程序把過濾後的結果爲詞典:

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

一個片段顯示出它的用途:

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

可以使用合同解析器是這樣的:

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

這將排除計算性能,但包括C#6只獲得屬性和一組方法的所有屬性。

4

Json.net確實能夠在沒有屬性或合約解析器的情況下有條件地序列化屬性。如果你不想讓你的項目對Json.net有依賴,這是特別有用的。

作爲每Json.net documentation

有條件地序列的屬性,添加與 返回布爾相同的名稱的屬性的方法,然後用 ShouldSerialize前綴的方法名。該方法的結果確定 屬性是否已序列化。如果方法返回true,那麼屬性 將被序列化,如果它返回false,則該屬性將被跳過 。

相關問題