Есть ли способ игнорировать свойства "только для получения" в Json.NET без использования атрибутов JsonIgnore?
Есть ли способ игнорировать свойства только для получения, используя сериализатор Json.NET, но без использования 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;
}
}
Нужно ли добавлять [JsonIgnore]
для всех них (у меня также есть много других классов), или есть лучший способ игнорировать все свойства только для получения?
4 ответа
Вы можете сделать это путем реализации пользовательских 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"}
Используйте режим OptIn JSON.net, и вам нужно только украсить свойства, которые вы хотите сериализовать. Это не так хорошо, как автоматическое отключение всех свойств только для чтения, но это может сэкономить вам немного работы.
[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);
Вы можете использовать распознаватель контракта следующим образом:
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, получит только свойства и все свойства с помощью заданного метода.
Json.net имеет возможность условно сериализовать свойства без атрибута или средства разрешения контрактов. Это особенно полезно, если вы не хотите, чтобы ваш проект зависел от Json.net.
Согласно документации Json.net
Чтобы условно сериализовать свойство, добавьте метод, который возвращает логическое значение с тем же именем, что и у свойства, а затем добавьте префикс метода к методу ShouldSerialize. Результат метода определяет, будет ли свойство сериализовано. Если метод возвращает значение true, свойство будет сериализовано, если оно возвращает значение false, свойство будет пропущено.