c# - 包含字段类型的 .net JSON 或 XML 对象序列化和创建

标签 c# .net xml json serialization

我正在尝试将动态 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/

相关文章:

c# - 反射 - 获取属性名称

c# - Xaf 新项目有黄色三角形

.net - 是什么让 CLR 显示断言?

xml - XSD 属性 NILLABLE 不起作用

java - JAXB 解码到列表

c# - C# 表单元素的动态命名

c# - 在代码隐藏中创建 jqGrid 列模型

.net - 将菜单按钮及其功能与表单同步

.net - VS2008 - 为版本号添加字母(即 1.1.1.12-Dev)

ruby-on-rails - 使用 Ruby on Rails (1.4GB) 解析非常大的 XML 文件——有没有比 SAXParser 更好的方法?