我正在尝试将动态 DTO 映射到 JSON 或 XML,但要获得有关字段类型的信息。 所以我很想知道是否有可能从看起来像这样的对象:
public class AddressDto
{
public string Street { get; set; }
}
public class UserInfoDto
{
public string UserName { get; set; }
public int Age { get; set; }
public AddressDto Address { get; set; }
}
要在 JSON(或 XML)中获取类似这样的内容:
{
"fieldType": "UserInfoDto"
"objectValue":
{
{
"fieldType": "string",
"fieldName": "UserName",
"fieldValue": "John Doe",
},
{
"fieldType": "integer",
"fieldName": "Age",
"fieldValue": "27",
},
{
"fieldType": "AddressDto",
"fieldName": "Address",
"fieldValue": {
"fieldType": "string",
"fieldName": "Street",
"fieldValue": "Lorem Ipsum"
}
}
}
}
...反之亦然。
最佳答案
是的,这是可能的,但您必须做一些工作来指示序列化程序如何格式化输出字符串。如果你想坚持使用内置的 .NET 序列化器,你可以使用 System.Runtime.Serialization.Json.DataContractJsonSerializer
来实现。类。
1- 创建 MetadataObject 类作为输出数据的包装对象
定义下面的类,用[DataContract]
标记所以它可以被序列化:
[DataContract]
public class MetadataObject
{
[DataMember(Name = "fieldType")]
public string FieldType { get; set; }
[DataMember(Name = "fieldName")]
public string FieldName { get; set; }
[DataMember(Name = "fieldValue")]
public object FieldValue { get; set; }
}
2- 告诉序列化程序如何序列化父 (UserInfoDto) 对象
为此,您需要拥有 UserInfoDto
对象实现 ISerializable
接口(interface)(更具体地说,GetObjectData()
方法)并将其标记为 [Serializable]
.您还需要包含此类将包含的所有自定义类型。在这种情况下,它将是 AddressDto
类型,以及 List<MedataObject>
在 GetObjectData()
中构建方法。最后一个类看起来像这样:
[KnownType(typeof(AddressDto))]
[KnownType(typeof(List<MetadataObject>))]
[Serializable]
public class UserInfoDto : ISerializable
{
public string UserName { get; set; }
public int Age { get; set; }
public AddressDto Address { get; set; }
public void GetObjectData(SerializationInfo info, StreamingContext context)
{
var nodes = this.GetType().GetProperties().Select(property =>
{
return new MetadataObject
{
FieldType = property.PropertyType.Name,
FieldName = property.Name,
FieldValue = property.GetValue(this, null)
};
}).ToList();
info.AddValue("fieldType", this.GetType().Name);
info.AddValue("objectValue", nodes);
}
}
请注意 GetObjectData()
方法使用反射并创建一个 MetadataObject
每个属性的类。这样做的好处在于它使代码更通用一些。所以稍后,如果您决定需要更多类,例如 UserInfoDto
,您可以将此逻辑放在基类中,让其他类继承它。
3- 告诉序列化程序如何序列化子 (AddressDto) 对象
与UserInfoDto
相同,有子类工具ISerializable
并将其标记为 [Serializable]
:
[Serializable]
public class AddressDto : ISerializable
{
public string Street { get; set; }
public void GetObjectData(SerializationInfo info, StreamingContext context)
{
foreach (var property in this.GetType().GetProperties())
{
info.AddValue("fieldType", property.PropertyType.Name);
info.AddValue("fieldName", property.Name);
info.AddValue("fieldValue", property.GetValue(this, null));
}
}
}
4- 把它们放在一起
最后,像这样定义你的序列化器:
DataContractJsonSerializer serializer = new DataContractJsonSerializer(typeof(UserInfoDto));
var data = new UserInfoDto { Age = 30, UserName = "John" };
data.Address = new AddressDto { Street = "123 ABC" };
using (MemoryStream stream = new MemoryStream())
{
using (StreamReader reader = new StreamReader(stream))
{
serializer.WriteObject(stream, data);
stream.Position = 0;
var output = reader.ReadToEnd();
}
}
当你运行它时,output
看起来像这样:
{
"fieldType":"UserInfoDto",
"objectValue":[
{
"__type":"MetadataObject:#StackOverflow.Console",
"fieldName":"UserName",
"fieldType":"String",
"fieldValue":"John"
},
{
"__type":"MetadataObject:#StackOverflow.Console",
"fieldName":"Age",
"fieldType":"Int32",
"fieldValue":30
},
{
"__type":"MetadataObject:#StackOverflow.Console",
"fieldName":"Address",
"fieldType":"AddressDto",
"fieldValue":{
"__type":"AddressDto:#StackOverflow.Console",
"fieldType":"String",
"fieldName":"Street",
"fieldValue":"123 ABC"
}
}
]
}
请注意 __type
属性由序列化程序自动生成。如果您使用的是 .NET 4.5,则可以 try the following to have it not be part of the output (如果需要将字符串反序列化回对象,您可能会需要它们)
关于c# - 包含字段类型的 .net JSON 或 XML 对象序列化和创建,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/25631194/