我正在寻找一种使用Json.Net部分序列化模型到Json的方法。我想在父对象的属性上定义的部分序列化应该是什么样子。因此,对于不同的父模型,部分序列化看起来是不同的。为了说明我在这里想要的,一些代码:
private class MyTestObject
{
[SerializeOnly("TestValue1")]
[SerializeOnly("TestValue3")]
public ComplexTestObject Property1 { get; set; }
public MyTestObject()
{
Property1 = new ComplexTestObject();
}
}
private class ComplexTestObject
{
public string TestValue1 { get; set; }
public string TestValue2 { get; set; }
public string TestValue3 { get; set; }
public ComplexTestObject()
{
TestValue1 = "value1";
TestValue2 = "value2";
TestValue3 = "value3";
}
}
现在,当我序列化类MyTestObject
的实例时,我想得到以下Json:
{
"Property1" : {
"TestValue1" : "value1",
"TestValue3" : "value3",
}
}
您可以看到SerializeOnly
用于定义要序列化的属性。
要实现这一点,我可以创建一个SerializeOnlyAttribute
。当尝试在自定义序列化ContractResolver中使用它时,我只能看到特定成员的属性,因此我看不到任何SerializeOnlyAttribute
,因为它们驻留在父节点上。
是否有一个简单的方法来实现期望的行为与Json.Net?也许可以编写一个自定义的JsonConverter,但是如何构建这样只处理属性而仍然使用默认转换器?
可以分两部分解决:
- 创建一个自定义的JsonConverter,可以接受一系列属性的名称来序列化。
- 创建一个自定义ContractResolver,它查找至少应用了一个
[SerializeOnly]
属性的属性,并将自定义转换器应用于这些属性,传递从应用属性中收集的子属性名称列表。
解析器可能是这样的:
class CustomResolver : DefaultContractResolver
{
protected override IList<JsonProperty> CreateProperties(Type type, MemberSerialization memberSerialization)
{
IList<JsonProperty> props = base.CreateProperties(type, memberSerialization);
foreach (JsonProperty prop in props)
{
if (!prop.PropertyType.IsPrimitive && prop.PropertyType != typeof(string))
{
PropertyInfo pi = type.GetProperty(prop.UnderlyingName);
if (pi != null && pi.CanRead)
{
var childPropertiesToSerialize = pi.GetCustomAttributes<SerializeOnly>()
.Select(att => att.PropertyName);
if (childPropertiesToSerialize.Any())
{
prop.Converter = new CustomConverter(childPropertiesToSerialize);
}
}
}
}
return props;
}
}
这里是转换器:
class CustomConverter : JsonConverter
{
private HashSet<string> propertiesToSerialize;
public CustomConverter(IEnumerable<string> propertiesToSerialize)
{
this.propertiesToSerialize = new HashSet<string>(propertiesToSerialize);
}
public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
{
writer.WriteStartObject();
foreach (PropertyInfo prop in value.GetType().GetProperties())
{
if (prop.CanRead && propertiesToSerialize.Contains(prop.Name))
{
writer.WritePropertyName(prop.Name);
serializer.Serialize(writer, prop.GetValue(value));
}
}
writer.WriteEndObject();
}
public override bool CanRead
{
get { return false; }
}
public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
{
throw new NotImplementedException();
}
public override bool CanConvert(Type objectType)
{
throw new NotImplementedException();
}
}
演示:class Program
{
static void Main(string[] args)
{
var test = new MyTestObject();
var settings = new JsonSerializerSettings();
settings.ContractResolver = new CustomResolver();
settings.Formatting = Formatting.Indented;
var json = JsonConvert.SerializeObject(test, settings);
Console.WriteLine(json);
}
class MyTestObject
{
[SerializeOnly("TestValue1")]
[SerializeOnly("TestValue3")]
public ComplexTestObject Property1 { get; set; }
[SerializeOnly("TestValue2")]
public ComplexTestObject Property2 { get; set; }
public MyTestObject()
{
Property1 = new ComplexTestObject();
Property2 = new ComplexTestObject();
}
}
class ComplexTestObject
{
public string TestValue1 { get; set; }
public string TestValue2 { get; set; }
public string TestValue3 { get; set; }
public ComplexTestObject()
{
TestValue1 = "value1";
TestValue2 = "value2";
TestValue3 = "value3";
}
}
}
输出:{
"Property1": {
"TestValue1": "value1",
"TestValue3": "value3"
},
"Property2": {
"TestValue2": "value2"
}
}
小提琴:https://dotnetfiddle.net/Fj7QcW
c#已经有一个属性来帮助你实现这个
https://msdn.microsoft.com/en-us/library/system.web.script.serialization.scriptignoreattribute (v = vs.110) . aspx
[ScriptIgnore]
public string MyParam{get;set;}