![](/img/trans.png)
[英]C# Xml Serialization: Serialize Class properties as attributes to the parent class
[英]C# JSON Custom Serialization of Class Including Attributes of Members/Properties
我有许多类需要序列化为标准格式,如下所示:
Class 示例:
public class MyClass
{
[JsonProperty("prop1")]
public string Prop1 { get; set; }
[JsonProperty("prop2")]
[CustomType("somevalue")]
public string Prop2 { get; set; }
//
//
[JsonProperty("propn")]
[CustomType("anothervalue")]
public string PropN { get; set; }
}
我需要我的 JSON 看起来像这样:
{
"AllProps": [
{
"Key": "prop1",
"Value": "value of prop1",
"Type": "0" //default to "0" if CustomType attribute is null
},
{
"Key": "prop2",
"Value": "value of prop2",
"Type": "somevalue"
},
{
"Key": "propn",
"Value": "value of propn",
"Type": "anothervalue"
}
]
}
如何将这些“CustomType”属性带入我的 JObject/JTokens?
您可以创建一个自定义JsonConverter
,通过使用存储在 Json.NET 自己的JsonObjectContract
中的元数据以所需格式序列化您的MyClass
,以获取所有可序列化属性及其属性的列表。
首先,定义以下转换器和属性:
[System.AttributeUsage(System.AttributeTargets.Property | System.AttributeTargets.Field, AllowMultiple = false, Inherited = true)]
public class CustomTypeAttribute : System.Attribute
{
public CustomTypeAttribute(string type) => this.Type = type;
public string Type { get; set; }
}
public class ObjectAsAllPropsConverter<TBase> : JsonConverter
{
const string AllPropsName = "AllProps";
const string KeyName = "Key";
const string ValueName = "Value";
const string TypeName = "Type";
const string DefaultType = "0";
static IContractResolver DefaultResolver { get; } = JsonSerializer.CreateDefault().ContractResolver;
readonly IContractResolver resolver;
public ObjectAsAllPropsConverter() : this(DefaultResolver) { }
public ObjectAsAllPropsConverter(IContractResolver resolver) => this.resolver = resolver ?? throw new ArgumentNullException(nameof(resolver));
public override bool CanConvert(Type objectType)
{
if (objectType.IsPrimitive || objectType == typeof(string) || !typeof(TBase).IsAssignableFrom(objectType))
return false;
return resolver.ResolveContract(objectType) is JsonObjectContract;
}
public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
{
var contract = (JsonObjectContract)serializer.ContractResolver.ResolveContract(value.GetType());
writer.WriteStartObject();
writer.WritePropertyName(AllPropsName);
writer.WriteStartArray();
foreach (var property in contract.Properties.Where(p => ShouldSerialize(p, value)))
{
var propertyValue = property.ValueProvider.GetValue(value);
if (propertyValue == null && (serializer.NullValueHandling == NullValueHandling.Ignore || property.NullValueHandling == NullValueHandling.Ignore))
continue;
writer.WriteStartObject();
writer.WritePropertyName(KeyName);
writer.WriteValue(property.PropertyName);
writer.WritePropertyName(ValueName);
if (propertyValue == null)
writer.WriteNull();
else if (property.Converter != null && property.Converter.CanWrite)
property.Converter.WriteJson(writer, propertyValue, serializer);
else
serializer.Serialize(writer, propertyValue);
writer.WritePropertyName(TypeName);
var type = property.AttributeProvider.GetAttributes(typeof(CustomTypeAttribute), true).Cast<CustomTypeAttribute>().SingleOrDefault()?.Type ?? DefaultType;
writer.WriteValue(type);
writer.WriteEndObject();
}
writer.WriteEndArray();
writer.WriteEndObject();
}
protected virtual bool ShouldSerialize(JsonProperty property, object value) =>
property.Readable && !property.Ignored && (property.ShouldSerialize == null || property.ShouldSerialize(value));
public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer) => throw new NotImplementedException();
}
现在您可以序列化为 JSON 如下:
var myClass = new MyClass
{
Prop1 = "value of prop1",
Prop2 = "value of prop2",
PropN = "value of propn",
};
var settings = new JsonSerializerSettings
{
Converters = { new ObjectAsAllPropsConverter<object>() },
};
var json = JsonConvert.SerializeObject(myClass, Formatting.Indented, settings);
结果是:
{
"AllProps": [
{
"Key": "prop1",
"Value": "value of prop1",
"Type": "0"
},
{
"Key": "prop2",
"Value": "value of prop2",
"Type": "somevalue"
},
{
"Key": "propn",
"Value": "value of propn",
"Type": "anothervalue"
}
]
}
或者,如果您出于某种原因需要序列化为中间JObject
,您可以这样做:
var token = JObject.FromObject(myClass, JsonSerializer.CreateDefault(settings));
笔记:
我只实现了序列化,因为问题中没有要求反序列化。
转换器的CanConvert
方法会自动检查传入的 object 类型是否会被序列化为 JSON object。 如果您希望所有 JSON 对象都以AllProps
格式序列化,请使用ObjectAsAllPropsConverter<object>
。 如果您只想以这种格式序列化某个 .NET 类型,请将泛型约束限制为此类型,例如
var settings = new JsonSerializerSettings { Converters = { new ObjectAsAllPropsConverter<MyClass>() }, };
演示小提琴在这里。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.