是的,這是可能的,但你必須做一些工作來指示序列化程序如何格式化輸出字符串。如果你想要使用內置的.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
對象ct執行ISerializable
接口(更具體地說,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(如果字符串需要反序列化回一個對象,你很有可能需要它們)
你想這是自動的嗎?因爲我有一個手動的解決方案(實際上很乏味)。 – 2014-09-02 21:05:30
自動會更好。我可以通過手動使用反射來生成一些自定義JSON或XML,但是當我需要將它轉換回源對象時,我遇到了一些問題。所以如果你有任何解決方案可以隨意分享。 – ShP 2014-09-03 09:24:38