52

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

4 に答える 4

83

これを行うには、カスタムを実装し、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"}
于 2013-08-31T13:54:12.707 に答える
16

JSON.net の OptIn モードを使用すると、シリアル化するプロパティを装飾するだけで済みます。これは、すべての読み取り専用プロパティを自動的にオプトアウトするほどではありませんが、作業を節約できます。

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

    public string nonSerializedProp { get; set; }
}

更新: リフレクションを使用して別の可能性を追加

上記の解決策がまだ探しているものではない場合は、リフレクションを使用して、シリアル化される辞書オブジェクトを作成できます。もちろん、以下の例は単純なクラスに対してのみ機能するため、クラスに他のクラスが含まれている場合は再帰を追加する必要があります。これにより、少なくとも正しい方向に進むはずです。

フィルタリングされた結果を辞書に入れるサブルーチン:

    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);
于 2013-08-31T02:22:45.383 に答える
12

次のようなコントラクト リゾルバーを使用できます。

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 get only プロパティと set メソッドを持つすべてのプロパティが含まれます。

于 2015-12-06T00:32:38.473 に答える
10

Json.net には、属性やコントラクト リゾルバーを使用せずにプロパティを条件付きでシリアル化する機能があります。これは、プロジェクトを Json.net に依存させたくない場合に特に便利です。

Json.netのドキュメントに従って

プロパティを条件付きでシリアル化するには、プロパティと同じ名前のブール値を返すメソッドを追加し、メソッド名の前に ShouldSerialize を付けます。メソッドの結果によって、プロパティがシリアル化されているかどうかが決まります。メソッドが true を返す場合、プロパティはシリアル化され、false を返す場合、プロパティはスキップされます。

于 2016-12-22T07:53:33.810 に答える