有没有办法忽略使用Json.NET序列化程序的get-only属性但不使用JsonIgnore属性?
例如,我有一个具有这些get属性的类:
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;
}
}
Run Code Online (Sandbox Code Playgroud)
我是否需要添加[JsonIgnore]到所有这些(我还有许多其他类),或者有更好的方法来忽略所有get-only属性?
Bri*_*ers 69
您可以通过实现自定义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();
}
}
Run Code Online (Sandbox Code Playgroud)
这是一个演示如何使用它的测试程序:
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); }
}
}
Run Code Online (Sandbox Code Playgroud)
这是上面的输出.请注意,只读属性LowerCaseName不包含在输出中.
{"Id":2,"Name":"Joe Schmoe"}
Run Code Online (Sandbox Code Playgroud)
Lat*_*y81 14
使用JSON.net的OptIn模式,您只需要装饰要序列化的属性.这不如自动选择所有只读属性,但它可以为您节省一些工作.
[JsonObject(MemberSerialization.OptIn)]
public class MyClass
{
[JsonProperty]
public string serializedProp { get; set; }
public string nonSerializedProp { get; set; }
}
Run Code Online (Sandbox Code Playgroud)
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;
}
Run Code Online (Sandbox Code Playgroud)
显示其用途的片段:
SampleClass sampleClass = new SampleClass();
sampleClass.Hotkey = Keys.A;
var toSerialize = ConvertToDictionary(sampleClass);
String resultText = JsonConvert.SerializeObject(toSerialize);
Run Code Online (Sandbox Code Playgroud)
您可以使用这样的合同解析器:
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;
}
}
Run Code Online (Sandbox Code Playgroud)
它将排除计算的属性,但包括C#6 get only属性和所有使用set方法的属性.
Json.net确实能够在没有属性或合同解析器的情况下有条件地序列化属性.如果您不希望您的项目依赖于Json.net,这将特别有用.
要有条件地序列化属性,请添加一个返回与该属性同名的布尔值的方法,然后使用ShouldSerialize作为方法名称的前缀.方法的结果确定属性是否已序列化.如果该方法返回true,则该属性将被序列化,如果它返回false,则将跳过该属性.