使用 DataContractSerializer 的接口中的显式类型

Posted

技术标签:

【中文标题】使用 DataContractSerializer 的接口中的显式类型【英文标题】:Explicit types from interfaces using DataContractSerializer 【发布时间】:2021-07-10 11:46:09 【问题描述】:

我正在使用 WPF 中的 DataContractSerializer 编写 XML。我需要 XML 尽可能干净(不需要反序列化回同一个应用程序),没有任何命名空间等。 这主要是可行的,但是当我的 Arrays/Lists/IEnumerables 是接口类型时,我遇到了问题。

作为最小的工作示例,我想序列化以下数据结构:

namespace HR

    public interface IEmployee
     
        string FirstName  get; 
        string LastName  get; 
    


    [DataContract(Namespace = "")]
    [KnownType(typeof(Employee))]
    public class Employee : IEmployee
    
        public Employee(string firstName, string lastName)
        
            FirstName = firstName;
            LastName = lastName;
        

        [DataMember]
        public string FirstName  get; set; 
        [DataMember]
        public string LastName  get; set; 
    


namespace Business

    [DataContract(Namespace ="")]
    public class Company
    
        [DataMember]
        public string CompanyName  get; set; 

        [DataMember]
        public IEmployee CEO  get; set; 

        [DataMember]
        public IEnumerable<IEmployee> Employees;
    

我序列化的方式如下:

namespace Program

    static void Main(string[] args)
    
        Employee jimApple = new Employee("Jim", "Apple");
        Employee bob = new Employee("Bob", "the Builder");
        Company company = new Company
        
            CEO = jimApple,
            Employees = new List<Employee>  jimApple, bob 
        ;

        var outputPath = System.IO.Path.Combine(System.IO.Directory.GetCurrentDirectory(), "Test.xml");
        Stream outputStream = new System.IO.FileStream(outputPath, FileMode.Create);
        using (var writer = XmlWriter.Create(outputStream, new XmlWriterSettings  Indent = true ))
        
            var serializer = new DataContractSerializer(typeof(Company));
            serializer.WriteObject(writer, company);
        
    

写出来的内容如下:

<?xml version="1.0" encoding="utf-8"?>
<Company xmlns:i="http://www.w3.org/2001/XMLSchema-instance">
  <CEO xmlns="" i:type="Employee">
    <FirstName>Jim</FirstName>
    <LastName>Apple</LastName>
  </CEO>
  <CompanyName i:nil="true" />
  <Employees xmlns:d2p1="http://schemas.microsoft.com/2003/10/Serialization/Arrays">
    <d2p1:anyType xmlns="" i:type="Employee">
      <FirstName>Jim</FirstName>
      <LastName>Apple</LastName>
    </d2p1:anyType>
    <d2p1:anyType xmlns="" i:type="Employee">
      <FirstName>Bob</FirstName>
      <LastName>the Builder</LastName>
    </d2p1:anyType>
  </Employees>
</Company>

现在这已经差不多好了,但我需要 &lt;d2p1:anyType xmlns="" i:type="Employee"&gt; 行看起来像 &lt;Employee&gt;。另外我更喜欢去掉xmlns:d2p1="http://schemas.microsoft.com/2003/10/Serialization/Arrays"

我一直在研究 DataContractResolver 类来做这种事情,但没有运气。有什么方法可以实现上述目标?

【问题讨论】:

【参考方案1】:

您应该考虑使用自定义集合类型并使用CollectionDataContract 属性对其进行装饰:

[DataContract(Namespace = "")]
public class Company

    [DataMember]
    public string CompanyName  get; set; 

    [DataMember]
    public IEmployee CEO  get; set; 

    [DataMember]
    public EmployeeCollecion Employees;


[CollectionDataContract(ItemName = "Employee", Namespace = "")]
public class EmployeeCollecion : List<Employee>

    public EmployeeCollecion() : base()  

    public EmployeeCollecion(int capacity) : base(capacity)  

    public EmployeeCollecion(IEnumerable<Employee> collection) : base(collection)  

这可能是您使用DataContractResolver 所能达到的程度。如果您需要自定义序列化并且“不需要反序列化回同一个应用程序”,那么自己进行序列化似乎更容易。

【讨论】:

它确实有效,但我有点难过它需要更改数据结构来实现它 @Yellow:嗯,就像我说的,如果你想要最大的灵活性,你最好编写自己的自定义序列化程序。

以上是关于使用 DataContractSerializer 的接口中的显式类型的主要内容,如果未能解决你的问题,请参考以下文章

使用 DataContractSerializer 时设置属性的初始值

使用 DataContractSerializer 和 XmlDictionaryWriter 序列化 JObject 后崩溃

在原语列表上使用 DataContractSerializer 的自定义元素名称

使用 DataContractSerializer 的接口中的显式类型

使用 DataContractSerializer 序列化没有命名空间的对象

如何使用 DataContractSerializer 从 XMLDocument 的单个节点反序列化?