如果我有以下类,我想使用JSON.NET序列化:
[DataContract]
public class Thing
{
[DataMember(Name = "@context")]
public string Context => "http://schema.org"
}
[DataContract]
public class Organization : Thing
{
[DataMember(Name = "address")]
public Address Address { get; set; }
...
}
[DataContract]
public class Address : Thing
{
...
}
当我使用JSON.NET序列化组织时,我得到:
{
"@context": "http://schema.org",
"address": {
"@context": "http://schema.org",
...
}
...
}
确保@context
属性仅出现在顶级Organization
对象而不是Address
对象中的最有效方法是什么?
答案 0 :(得分:2)
如果Organization
是Thing
的唯一顶级后代,并且序列化对象中也没有Organization
类型的字段,则可以通过定义ShouldSerializeContext
轻松完成此操作在Thing
中如下:
[DataContract]
public class Thing
{
[DataMember(Name = "@context")]
public string Context => "http://schema.org";
public bool ShouldSerializeContext() { return this is Organization; }
}
演示:https://dotnetfiddle.net/GjmfbA
如果Thing
的任何后代可能充当根对象,则可能需要实现自定义转换器。在此转换器的WriteJson
方法中,您可以过滤要序列化的属性。要从除根对象以外的所有属性中删除Context
属性,请检查writer.Path
,这将是根对象的空字符串:
[DataContract]
[JsonConverter(typeof(NoContextConverter))]
public class Thing
{
[DataMember(Name = "@context")]
public string Context => "http://schema.org";
}
// ...............
public class NoContextConverter : JsonConverter
{
public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
{
var props = value.GetType().GetProperties()
.Where(p => Attribute.IsDefined(p, typeof(DataMemberAttribute)))
.ToList();
if (writer.Path != "")
props.RemoveAll(p => p.Name == "Context");
writer.WriteStartObject();
foreach (var prop in props)
{
writer.WritePropertyName(prop.GetCustomAttribute<DataMemberAttribute>().Name);
serializer.Serialize(writer, prop.GetValue(value, null));
}
writer.WriteEndObject();
}
public override bool CanConvert(Type objectType)
{
return typeof(Thing).IsAssignableFrom(objectType);
}
public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
{
throw new NotImplementedException();
}
}
演示:https://dotnetfiddle.net/cIlXID
N.B。出于某种原因,dotnetfiddle.net不允许使用DataContractAttribute
中的DataMemberAttribute
和System.Runtime.Serialization
,因此我必须在此演示中注释掉相关的行。
答案 1 :(得分:0)
虽然@ DimitryEgorov的答案可能是正确的方法,但它使用反射使其变慢。在下面的解决方案中,我使用StringBuilder
在最终的JSON上进行字符串替换。
private const string ContextPropertyJson = "\"@context\":\"http://schema.org\",";
public override string ToString() => RemoveAllButFirstContext(
JsonConvert.SerializeObject(this, new JsonSerializerSettings));
private static string RemoveAllButFirstContext(string json)
{
var stringBuilder = new StringBuilder(json);
var startIndex = ContextPropertyJson.Length + 1;
stringBuilder.Replace(
ContextPropertyJson,
string.Empty,
startIndex,
stringBuilder.Length - startIndex - 1);
return stringBuilder.ToString();
}