【问题标题】:How to selectively exclude a property from serialization based on the parent class type如何根据父类类型有选择地从序列化中排除属性
【发布时间】:2015-01-08 04:23:31
【问题描述】:

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

我尝试过使用堆栈跟踪,但它只告诉我 JSON 对象正在调用 ShouldSerialize 方法。我不需要知道什么叫ShouldSerialize,我需要知道ShouldSerialize属于什么父类,比如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";
    }
}

【问题讨论】:

  • 你能用构造函数参数传递这些信息吗?
  • 为什么 SharedClass 在您的示例中是一个字符串?非常混乱...
  • 没有可以用来阻止 JSON.NET 序列化属性的属性吗?也许[NonSerialized] 有效。
  • 你也可以使用继承。
  • @Dirk 如果没有,您应该创建一个自定义属性而不是前缀。

标签: c# json.net


【解决方案1】:

正如 Lasse Karlsen 在 cmets 中指出的,如果您的 SharedClass 没有对其父类的引用,则该类中的 ShouldSerializeSomeValue() 方法无法知道父类是什么。

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

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

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);
    }
}

这是上面演示的输出。您会注意到,Foo 内的 SharedClass 实例上的 SomeValue 属性未包含在输出中,但它包含在 Bar 内的实例中。

{
  "Foo": {
    "Shared": {
      "SomeOtherValue": "foo2"
    }
  },
  "Bar": {
    "Shared": {
      "SomeValue": "bar1",
      "SomeOtherValue": "bar2"
    }
  }
}

【讨论】:

  • 是的,这正是我要找的。不幸的是,我仅限于使用 Newtonsoft.Json 库。
  • Json.Net 和 Newtonsoft.Json 是同一个库。因此,如果您已经在使用这个库,那么您应该能够使用这个解决方案。试一试。
  • 抱歉耽搁了,有一个不同的任务需要处理。最初,我虽然您只是在 Json.Net 上展示了 OmitPropertiesConverter 的示例构成。通读我现在明白了。我试过你的代码,它正是我需要的。谢谢!
  • 不用担心;很高兴我能提供帮助。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2018-06-21
  • 2012-07-19
相关资源
最近更新 更多