C# 有没有办法在不使用 JsonIgnore 属性的情况下忽略 Json.NET 中的 get-only 属性?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/18543482/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Is there a way to ignore get-only properties in Json.NET without using JsonIgnore attributes?
提问by Jaex
Is there a way to ignore get-only properties using the Json.NETserializer but without using JsonIgnore
attributes?
有没有办法使用Json.NET序列化程序忽略仅获取属性但不使用JsonIgnore
属性?
For example, I have a class with these get properties:
例如,我有一个具有这些 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;
}
}
Do I need to add [JsonIgnore]
to all of them (I also have many other classes), or there is better way to ignore all get-only properties?
我是否需要添加[JsonIgnore]
到所有这些(我还有许多其他类),或者有更好的方法来忽略所有 get-only 属性?
采纳答案by Brian Rogers
You can do this by implementing a custom IContractResolver
and using that during serialization. If you subclass the DefaultContractResolver
, this becomes very easy to do:
您可以通过实现自定义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();
}
}
Here is a test program demonstrating how to use it:
这是一个演示如何使用它的测试程序:
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); }
}
}
Here is the output of the above. Notice that the read-only property LowerCaseName
is not included in the output.
这是上面的输出。请注意,LowerCaseName
输出中不包含只读属性。
{"Id":2,"Name":"Joe Schmoe"}
回答by Lathejockey81
Use the OptIn mode of JSON.net and you'll only need to decorate the properties you want to serialize. This isn't as good as automatically opting out all read only properties, but it can save you some work.
使用 JSON.net 的 OptIn 模式,您只需要装饰要序列化的属性。这不如自动选择退出所有只读属性好,但它可以为您节省一些工作。
[JsonObject(MemberSerialization.OptIn)]
public class MyClass
{
[JsonProperty]
public string serializedProp { get; set; }
public string nonSerializedProp { get; set; }
}
Udate: Added another possibility using reflection
Udate:使用反射添加了另一种可能性
If the above solution still isn't quite what you're looking for, you could use reflection to make dictionary objects which would then be serialized. Of course the example below will only work for simple classes, so you would need to add recursion if your classes contain other classes. This should at least point you in the right direction.
如果上述解决方案仍然不是您想要的,您可以使用反射来制作字典对象,然后将其序列化。当然,下面的示例仅适用于简单的类,因此如果您的类包含其他类,则需要添加递归。这至少应该为您指明正确的方向。
The subroutine to put the filtered result into a dictionary:
将过滤结果放入字典的子程序:
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;
}
A snippet showing its use:
显示其用途的片段:
SampleClass sampleClass = new SampleClass();
sampleClass.Hotkey = Keys.A;
var toSerialize = ConvertToDictionary(sampleClass);
String resultText = JsonConvert.SerializeObject(toSerialize);
回答by Johan Larsson
You can use a contract resolver like this:
您可以使用这样的合同解析器:
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;
}
}
It will exclude calculated properties but include C#6 get only properties and all properties with a set method.
它将排除计算属性,但包括 C#6 get only properties 和所有具有 set 方法的属性。
回答by Mark
Json.net does have the ability to conditionally serialize properties without an attribute or contract resolver. This is especially useful if you don't want your project to have a dependency on Json.net.
Json.net 确实能够在没有属性或合同解析器的情况下有条件地序列化属性。如果您不希望您的项目依赖于 Json.net,这将特别有用。
As per the Json.net documentation
To conditionally serialize a property, add a method that returns boolean with the same name as the property and then prefix the method name with ShouldSerialize. The result of the method determines whether the property is serialized. If the method returns true then the property will be serialized, if it returns false then the property will be skipped.
要有条件地序列化属性,请添加一个方法,该方法返回与该属性同名的布尔值,然后在方法名称前加上 ShouldSerialize。方法的结果决定了属性是否被序列化。如果该方法返回 true 则该属性将被序列化,如果它返回 false 则该属性将被跳过。