问题
I'm trying to serialize only the inherited properties of a class using json.net. I'm aware of the [JsonIgnore] attribute, but I only want to do ignore them on certain occasion, so I used a custom JsonConverter instead.
Here's my class:
public class EverythingButBaseJsonConverter : JsonConverter
{
public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
{
// Find properties of inherited class
var classType = value.GetType();
var classProps = classType.GetProperties(BindingFlags.DeclaredOnly | BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic).ToList();
// Remove the overrided properties
classProps.RemoveAll(t =>
{
var getMethod = t.GetGetMethod(false);
return (getMethod.GetBaseDefinition() != getMethod);
});
// Get json data
var o = (JObject)JToken.FromObject(value);
// Write only properties from inhertied class
foreach (var p in o.Properties().Where(p => classProps.Select(t => t.Name).Contains(p.Name)))
p.WriteTo(writer);
}
public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
{
throw new NotImplementedException("");
}
public override bool CanRead
{
get { return false; }
}
public override bool CanConvert(Type objectType)
{
return true;
}
}
When doing a simple o.WriteTo(writer); it give the same result as not using a converter. When iterating through properties and using WriteTo on the properties, it works fine for base type (int, string, etc), but I'm having problem with collections.
Expected:
{
"Type": 128,
"Time": [
1,
2,
],
"Pattern": 1,
"Description": ""
}
Got:
"Type": 128,
"Time": [
1,
2,
]"Pattern": 1,
"Description": ""
As you can see, the collection is missing the "," and endline portion. I'm also missing the global { } for the whole object.
I am doing things the correct way? Is there an easier way to get the result I want?
回答1:
Not sure why your code doesn't work (maybe a Json.NET bug?). Instead, you can remove the properties you don't want from the JObject
and write the entire thing in one call:
public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
{
// Find properties of inherited class
var classType = value.GetType();
var classProps = classType.GetProperties(BindingFlags.DeclaredOnly | BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic).ToList();
// Remove the overrided properties
classProps.RemoveAll(t =>
{
var getMethod = t.GetGetMethod(false);
return (getMethod.GetBaseDefinition() != getMethod);
});
// Get json data
var o = (JObject)JToken.FromObject(value);
// Remove all base properties
foreach (var p in o.Properties().Where(p => !classProps.Select(t => t.Name).Contains(p.Name)).ToList())
p.Remove();
o.WriteTo(writer);
}
Alternatively, you could create your own contract resolver and filter out base properties and members:
public class EverythingButBaseContractResolver : DefaultContractResolver
{
protected override JsonProperty CreateProperty(MemberInfo member, MemberSerialization memberSerialization)
{
if (member.ReflectedType != member.DeclaringType)
return null;
if (member is PropertyInfo)
{
var getMethod = ((PropertyInfo)member).GetGetMethod(false);
if (getMethod.GetBaseDefinition() != getMethod)
return null;
}
var property = base.CreateProperty(member, memberSerialization);
return property;
}
}
And then use it like:
var settings = new JsonSerializerSettings { ContractResolver = new EverythingButBaseContractResolver() };
var json = JsonConvert.SerializeObject(rootObject, Formatting.Indented, settings);
来源:https://stackoverflow.com/questions/30063259/how-to-serialize-only-inherited-properties-of-a-class-using-a-jsonconverter