27

オブジェクトの最初の深度レベルのみが必要です (子は必要ありません)。利用可能なライブラリがあれば喜んで使用します。ほとんどのライブラリは、再帰の深さに達すると、単に無視するのではなく、単に例外をスローします。これが不可能な場合、特定のデータ型が指定された特定のメンバーのシリアル化を無視する方法はありますか?

編集:次のようなオブジェクトがあるとしましょう:

class MyObject
{
    String name = "Dan";
    int age = 88;
    List<Children> myChildren = ...(lots of children with lots of grandchildren);
}

次のようなオブジェクトを返すために、子 (複合型であっても) を削除したいと考えています。

class MyObject
{
    String name = "Dan";
    int age = 88;
    List<Children> myChildren = null;
}
4

4 に答える 4

36

これは、Json.NETJsonWriterで、とシリアライザーの間の調整を使用して可能ContractResolverです。

カスタムJsonWriterは、オブジェクトの開始時にカウンターをインクリメントし、終了時に再びデクリメントします。

public class CustomJsonTextWriter : JsonTextWriter
{
    public CustomJsonTextWriter(TextWriter textWriter) : base(textWriter) {}

    public int CurrentDepth { get; private set; }

    public override void WriteStartObject()
    {
        CurrentDepth++;
        base.WriteStartObject();
    }

    public override void WriteEndObject()
    {
        CurrentDepth--;
        base.WriteEndObject();
    }
}

カスタムは、現在の深さを確認するために使用されるすべてのプロパティにContractResolver特別なShouldSerialize述語を適用します。

public class CustomContractResolver : DefaultContractResolver
{
    private readonly Func<bool> _includeProperty;

    public CustomContractResolver(Func<bool> includeProperty)
    {
        _includeProperty = includeProperty;
    }

    protected override JsonProperty CreateProperty(
        MemberInfo member, MemberSerialization memberSerialization)
    {
        var property = base.CreateProperty(member, memberSerialization);
        var shouldSerialize = property.ShouldSerialize;
        property.ShouldSerialize = obj => _includeProperty() &&
                                          (shouldSerialize == null ||
                                           shouldSerialize(obj));
        return property;
    }
}

次のメソッドは、これら2つのカスタムクラスがどのように連携するかを示しています。

public static string SerializeObject(object obj, int maxDepth)
{
    using (var strWriter = new StringWriter())
    {
        using (var jsonWriter = new CustomJsonTextWriter(strWriter))
        {
            Func<bool> include = () => jsonWriter.CurrentDepth <= maxDepth;
            var resolver = new CustomContractResolver(include);
            var serializer = new JsonSerializer {ContractResolver = resolver};
            serializer.Serialize(jsonWriter, obj);
        }
        return strWriter.ToString();
    }
}

次のテストコードは、最大深度をそれぞれ1レベルと2レベルに制限することを示しています。

var obj = new Node {
    Name = "one",
    Child = new Node {
        Name = "two",
        Child = new Node {
            Name = "three"
        }
    }
};
var txt1 = SerializeObject(obj, 1);
var txt2 = SerializeObject(obj, 2);

public class Node
{
    public string Name { get; set; }
    public Node Child { get; set; }
}
于 2012-05-04T18:16:28.103 に答える
1

リフレクションを使用してオブジェクトを検査し、必要に応じて各プロパティ値を変更するコピーを作成できます。偶然にも、この種のことを本当に簡単にする新しいライブラリを公開したばかりです。ここから入手できます: https://github.com/jamietre/IQObjectMapper

使用するコードの例を次に示します

var newInstance = ObjectMapper.Map(obj,(value,del) => {
    return value !=null && value.GetType().IsClass ?
        null :
        value;
    });

「Map」メソッドは、オブジェクトの各プロパティを繰り返し処理し、Func<object,IDelegateInfo>for each を呼び出します (プロパティ名、タイプなどのリフレクション情報を持つ IDelegateInfo)。この関数は、各プロパティの新しい値を返します。したがって、この例では、各プロパティの値をテストして、それがクラスかどうかを確認し、そうである場合は null を返します。そうでない場合は、元の値を返します。

それを行う別のより表現力豊かな方法:

var obj = new MyObject();

// map the object to a new dictionary        

var dict = ObjectMapper.ToDictionary(obj);

// iterate through each item in the dictionary, a key/value pair
// representing each property 

foreach (KeyValuePair<string,object> kvp in dict) {
    if (kvp.Value!=null && kvp.Value.GetType().IsClass) {
        dict[kvp.Key]=null;
    }
}

// map back to an instance

var newObject = ObjectMapper.ToNew<MyObject>(dict);

いずれの場合も、newInstance.myChildren(および値型でないその他のプロパティ) の値は null になります。このマッピングで発生するルールは簡単に変更できます。

お役に立てれば。ところで-あなたのコメントから、JSONは実際にはあなたの目標ではなく、それを達成するのに役立つとあなたが考えたもののように思えます. json で終わりたい場合は、この出力をシリアル化するだけです。

string json = JavaScriptSerializer.Serialize(newObject);

しかし、それが目的を達成するための単なる手段である場合、json は関与しません。CLR オブジェクトにとどまりたい場合は、JSON を仲介として使用する必要はありません。

于 2012-05-04T19:39:13.377 に答える