C# 如何用派生类序列化基类

C# 如何用派生类序列化基类,c#,serialization,C#,Serialization,你好, 我有以下示例代码: public class Vehicule { public string Name { get; set; } public Brand Brand { get; set; } } public class Car : Vehicule { public string Matriculation { get; set; } } public class Brand { public string Name { get; set;

你好,

我有以下示例代码:

public class Vehicule
{
    public string Name { get; set; }
    public Brand Brand { get; set; }
}
public class Car : Vehicule
{
    public string Matriculation { get; set; }
}



public class Brand
{
    public string Name { get; set; }
}
public class Renault : Brand
{
    public string Information { get; set; }
}
如果创建此实例:

var car = new Car { Name = "Clio", Matriculation = "XXX-XXX", Brand = new Renault { Name = "Renault", Information = "Contact Infos" } };
当我像那样序列化此对象时:

var serializer = new XmlSerializer(typeof(Car), new Type[] { typeof(Renault)});
serializer.Serialize(wr, car);
我得到这个:

<?xml version="1.0" encoding="utf-8"?>
<Car xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
  <Name>Clio</Name>
  <Brand xsi:type="Renault">
    <Name>Renault</Name>
    <Information>Contact Infos</Information>
  </Brand>
  <Matriculation>XXX-XXX</Matriculation>
</Car>
Xml:

<?xml version="1.0" encoding="utf-8"?>
<Vehicule xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
  <Name>Clio</Name>
  <Brand>
    <Name>Renault</Name>
  </Brand>
</Vehicule>

克利奥
雷诺
您能帮我获取好的Xml(仅适用于基本类型车辆和品牌)吗


非常感谢

您不能神奇地将派生类序列化为其基础,因为

“…序列化通过调用Object.getType()检查实例的类型 方法。此方法始终返回对象的确切类型。“

如果您确实只需要序列化基类,那么这里的解决方案是实现IXmlSerializable接口并创建您自己的自定义序列化程序

IXmlSerializable

再想一想。如果您可以绕过输出额外XML元素的限制,那么您就可以仅使用基类对象序列化派生类,方法是1)使用基类上的来告诉它需要哪些类型,或者2)使用获取类型列表的重载

编辑: 再仔细考虑一下,一种解决方法是在基对象上添加Clone()方法,然后序列化基对象的克隆

LinqPad代码

public class Vehicule
{
    public string Name { get; set; }
    public Brand Brand { get; set; }

    public Vehicule Clone()
    {
        return new Vehicule { Name = this.Name, Brand = new Brand { Name = this.Brand.Name } };
    }
}
public class Car : Vehicule
{
    public string Matriculation { get; set; }
}



public class Brand
{
    public string Name { get; set; }
}
public class Renault : Brand
{
    public string Information { get; set; }
}

void Main()
{   
    var car = new Car { Name = "Clio", Matriculation = "XXX-XXX", Brand = new Renault { Name = "Renault", Information = "Contact Infos" } };
    var vehicle = car as Vehicule;

    var serializer = new System.Xml.Serialization.XmlSerializer(typeof(Vehicule));

    XmlWriterSettings settings = new XmlWriterSettings
    {
        Encoding = new UnicodeEncoding(false, false),
        Indent = false,
        OmitXmlDeclaration = false
    };

    using(StringWriter textWriter = new StringWriter())
    using(XmlWriter xmlWriter = XmlWriter.Create(textWriter, settings)) {
        serializer.Serialize(xmlWriter, vehicle.Clone());
        textWriter.ToString().Dump();
    }
}

这是继承的问题之一,也是支持组合的另一个原因

我在一个移动应用程序上遇到了同样的问题,我有一个
Contact
类,它源自
ContactSummary
。存储库返回
Contact
实例,但在很多情况下,我只希望
ContactSummary
能够节省消息大小和数据使用量等。默认的Xml和Json序列化器只有在派生类具有基类的
[KnownType()]
属性时才能工作,但这仍然意味着所有这些额外的财产都要通过电线

使用继承实现可行的解决方案是有问题的,我不想求助于自定义序列化程序,如果解决方案是用复制构造函数和克隆属性污染DTO,那么为什么不将DTO改为使用组合呢

如果您可以控制DTO,那么将其重组为使用组合而不是继承可能是答案。在我的例子中,它相当简单

public class ContactSummary
{
    public string Name { get; set;}
    public string Phone { get; set; }
}

public class Contact
{
    public ContactSummary Summary { get; set; }
    // ... other properties here
}
在您的示例中,
Car
将需要包含对
Vehicle
的引用,而不是从它继承-类似于

[KnowTypes(typeof(Renault))]
public class Vehicle
{
    public string Name { get; set; }
    public Brand Brand { get; set; }
}

public class Car
{
    public Vehicle Vehicle { get; set; }
    public string Matriculation { get; set; }
}

然后,当您想要示例中的“base”类型时,只需序列化
Car.Vehicle

就可以了,因为XML序列化程序的工作方式决定了不需要一些手动工作。您可以创建一个基实例并将值映射到上面,或者在此处查看RichardOD的答案:感谢TyCobb提供这些信息
[KnowTypes(typeof(Renault))]
public class Vehicle
{
    public string Name { get; set; }
    public Brand Brand { get; set; }
}

public class Car
{
    public Vehicle Vehicle { get; set; }
    public string Matriculation { get; set; }
}