如何根据父类类型有选择地从序列化中排除属性

时间:2015-01-07 14:28:47

标签: c# json.net

我使用Newtonsoft.JSON库来序列化多个对象。在某些情况下,我不想序列化一个属性,所以我使用了ShouldSerialize前缀,这在大多数情况下都是很成功的。在一种情况下,我只想序列化一个属性,如果它属于一个特定的类。

我尝试过使用堆栈跟踪,但它只告诉我JSON对象正在调用ShouldSerialize方法。我不需要知道调用ShouldSerialize的内容,我需要知道ParentSerialize所属的父类,例如Parent.Child.ShouldSerialize。

如何使用下面的代码示例确定使用JSON对象时父类名称是什么?

class Foo
{
    public SharedClass SomeProperty
    {
           get;
           set;
    }
}

class Bar
{
    public SharedClass SomeProperty
    {
           get;
           set;
    }
}

class SharedClass
{
    public string SomeValue
    {
           get;
           set;
    }

    public bool ShouldSerializeSomeValue
    {
           //pseudo logic
           return ClassName == "Foo";
    }
}

1 个答案:

答案 0 :(得分:1)

正如Lasse Karlsen在评论中指出的那样,如果您的SharedClass没有对其父级的引用,则该类中的ShouldSerializeSomeValue()方法无法知道父级的内容上课是。

但是,如果您使用的是Json.Net 6.0 Release 6或更高版本,则可以使用自定义JsonConverter作为选择性地从共享类中省略属性(而不是使用{{1}的方法来解决此问题。然后在适当的父类中的ShouldSerialize()属性上放置[JsonConverter]属性,以指示该实例应省略哪些属性。

以下是更新的示例类定义的外观。您会注意到我在SharedClass上标记了SharedClass实例,表明它应该使用名为Foo的自定义转换器来省略OmitPropertiesConverter属性。 SomeValue上的SharedClass实例不使用转换器,因此该实例将正常序列化。

Bar

以下是class Foo { [JsonConverter(typeof(OmitPropertiesConverter), "SomeValue")] public SharedClass Shared { get; set; } } class Bar { public SharedClass Shared { get; set; } } class SharedClass { public string SomeValue { get; set; } public string SomeOtherValue { get; set; } } 的代码。它的构造函数接受一个OmitPropertiesConverter字符串,这是一个以逗号分隔的属性名列表,从序列化中排除。这会被拆分为一个数组,以便以后在propsToOmit方法中使用。 WriteJson方法获取WriteJson值,将其转换为SharedClass,然后在编写JObject之前以编程方式删除propsToOmit数组中的属性JObject

JsonWriter

这是一个简单的演示程序,它显示了转换器的运行情况:

class OmitPropertiesConverter : JsonConverter
{
    string[] propsToOmit;

    public OmitPropertiesConverter(string propsToOmit)
    {
        this.propsToOmit = propsToOmit.Split(new char[] {','},
                                             StringSplitOptions.RemoveEmptyEntries);
    }

    public override bool CanConvert(Type objectType)
    {
        return (objectType == typeof(SharedClass));
    }

    public override void WriteJson(JsonWriter writer, object value, 
                                   JsonSerializer serializer)
    {
        JObject jo = JObject.FromObject(value, serializer);

        // Note: ToList() is needed here to prevent "collection was modified" error
        foreach (JProperty prop in jo.Properties()
                                     .Where(p => propsToOmit.Contains(p.Name))
                                     .ToList())
        {
            prop.Remove();
        }

        jo.WriteTo(writer);
    }

    public override bool CanRead
    {
        get { return false; }
    }

    public override object ReadJson(JsonReader reader, Type objectType,
                                    object existingValue, JsonSerializer serializer)
    {
        throw new NotImplementedException();
    }
}

以上是上述演示的输出。您会注意到class Program { static void Main(string[] args) { var root = new { Foo = new Foo { Shared = new SharedClass { SomeValue = "foo1", SomeOtherValue = "foo2" } }, Bar = new Bar { Shared = new SharedClass { SomeValue = "bar1", SomeOtherValue = "bar2" } } }; string json = JsonConvert.SerializeObject(root, Formatting.Indented); Console.WriteLine(json); } } SomeValue实例上的SharedClass属性未包含在输出中,但它包含在Foo内的实例中。

Bar