使用 DataContractSerializer 的接口的显式类型

问题描述

我正在使用 WPF 中的 DataContractSerializer 编写 XML。我需要 XML 尽可能干净(不需要反序列化回同一个应用程序),没有任何命名空间等。 这主要是有效的,但是当我的数组/列表/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>

现在差不多好了,但我需要将 <d2p1:anyType xmlns="" i:type="Employee"> 行简单地看起来像 <Employee>。我也更喜欢去掉 xmlns:d2p1="http://schemas.microsoft.com/2003/10/Serialization/Arrays"

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

解决方法

您应该考虑使用自定义集合类型并使用 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 的程度。如果您需要自定义序列化并且“不需要反序列化回同一个应用程序”,那么您自己进行序列化似乎更容易。