c# - net - newtonsoft jsonproperty example
¿Hay alguna manera de ignorar las propiedades solo para obtener en Json.NET sin usar atributos JsonIgnore? (4)
Json.net tiene la capacidad de serializar condicionalmente propiedades sin un atributo o resolución de contrato. Esto es especialmente útil si no desea que su proyecto dependa de Json.net.
De acuerdo con la documentación de Json.net
Para serializar condicionalmente una propiedad, agregue un método que devuelva booleano con el mismo nombre que la propiedad y luego ponga el nombre del método en ShouldSerialize. El resultado del método determina si la propiedad está serializada. Si el método devuelve verdadero, la propiedad se serializará; si devuelve falso, la propiedad se omitirá.
¿Hay alguna manera de ignorar las propiedades solo para obtener el uso del serializador Json.NET pero sin utilizar los atributos JsonIgnore
?
Por ejemplo, tengo una clase con estas propiedades 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;
}
}
¿Tengo que agregar [JsonIgnore]
a todos ellos (también tengo muchas otras clases), o hay una mejor manera de ignorar todas las propiedades solo para obtener?
Puede hacerlo implementando un IContractResolver
personalizado y usándolo durante la serialización. Si subclasifica el DefaultContractResolver
, esto se vuelve muy fácil de hacer:
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();
}
}
Aquí hay un programa de prueba que demuestra cómo usarlo:
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); }
}
}
Aquí está el resultado de lo anterior. Observe que la propiedad de solo lectura LowerCaseName
no se incluye en la salida.
{"Id":2,"Name":"Joe Schmoe"}
Puede usar un resuelve de contrato como este:
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;
}
}
Excluirá las propiedades calculadas, pero incluye que C # 6 obtenga solo propiedades y todas las propiedades con un método establecido.
Use el modo OptIn de JSON.net y solo tendrá que decorar las propiedades que desea serializar. Esto no es tan bueno como optar automáticamente por todas las propiedades de solo lectura, pero puede ahorrarle algo de trabajo.
[JsonObject(MemberSerialization.OptIn)]
public class MyClass
{
[JsonProperty]
public string serializedProp { get; set; }
public string nonSerializedProp { get; set; }
}
Udate: se agregó otra posibilidad usando la reflexión
Si la solución anterior aún no es exactamente lo que está buscando, puede usar el reflejo para crear objetos del diccionario que luego se serializarían. Por supuesto, el siguiente ejemplo solo funcionará para clases simples, por lo que necesitaría agregar recursividad si sus clases contienen otras clases. Esto debería al menos apuntar en la dirección correcta.
La subrutina para poner el resultado filtrado en un diccionario:
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;
}
Un fragmento que muestra su uso:
SampleClass sampleClass = new SampleClass();
sampleClass.Hotkey = Keys.A;
var toSerialize = ConvertToDictionary(sampleClass);
String resultText = JsonConvert.SerializeObject(toSerialize);