如何根据父 class 类型有选择地从序列化中排除属性
How to selectively exclude a property from serialization based on the parent class type
我正在使用 Newtonsoft.JSON 库序列化多个对象。在某些情况下,我不想序列化一个属性,所以我使用了 ShouldSerialize 前缀,这在大多数情况下都非常成功。在一种情况下,我只想序列化属于特定 class 的属性。
我试过使用堆栈跟踪,但它只告诉我 JSON 对象正在调用 ShouldSerialize 方法。我不需要知道什么调用 ShouldSerialize,我需要知道父 class ShouldSerialize 属于什么,例如 Parent.Child.ShouldSerialize.
在使用下面的代码示例使用 JSON 对象时,如何确定父 class 名称是什么?
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";
}
}
正如 Lasse Karlsen 在评论中所指出的那样,如果您的 SharedClass
没有对其父级的引用,那么 [=52= 中的 ShouldSerializeSomeValue()
方法就没有办法了] 知道父级 class 是什么。
但是,如果您使用的是 Json.Net 6.0 Release 6 或更高版本,您可以通过使用自定义 JsonConverter
作为一种有选择地从共享 class 中省略属性的方法来解决这个问题(而不是使用 ShouldSerialize()
方法),然后将 [JsonConverter]
属性放在适当父 class 中的 SharedClass
属性上,以指示该实例应省略哪些属性。
更新后的示例 class 定义可能如下所示。您会注意到我在 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
,然后在将 JObject
写入之前以编程方式删除 propsToOmit
数组中的属性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 库序列化多个对象。在某些情况下,我不想序列化一个属性,所以我使用了 ShouldSerialize 前缀,这在大多数情况下都非常成功。在一种情况下,我只想序列化属于特定 class 的属性。
我试过使用堆栈跟踪,但它只告诉我 JSON 对象正在调用 ShouldSerialize 方法。我不需要知道什么调用 ShouldSerialize,我需要知道父 class ShouldSerialize 属于什么,例如 Parent.Child.ShouldSerialize.
在使用下面的代码示例使用 JSON 对象时,如何确定父 class 名称是什么?
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";
}
}
正如 Lasse Karlsen 在评论中所指出的那样,如果您的 SharedClass
没有对其父级的引用,那么 [=52= 中的 ShouldSerializeSomeValue()
方法就没有办法了] 知道父级 class 是什么。
但是,如果您使用的是 Json.Net 6.0 Release 6 或更高版本,您可以通过使用自定义 JsonConverter
作为一种有选择地从共享 class 中省略属性的方法来解决这个问题(而不是使用 ShouldSerialize()
方法),然后将 [JsonConverter]
属性放在适当父 class 中的 SharedClass
属性上,以指示该实例应省略哪些属性。
更新后的示例 class 定义可能如下所示。您会注意到我在 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
,然后在将 JObject
写入之前以编程方式删除 propsToOmit
数组中的属性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"
}
}
}