这里的结构有点复杂,所以请容忍我。我希望有一种方法去做你想做的事情,但是如果不可能的话,那就告诉我吧!
不幸的是,我从一开始就没有参与XML文件规范的设计过程,目标已经被移动了十几次,规范也不能被修改,这样我就可以更容易地完成任何规范的修改,因为任何规范的修改都是定价过高的(是的,甚至可以重命名XML元素!)
不管怎样,我离题了。
有两种不同类型的采购订单,它们的文件结构和处理逻辑略有不同,我试图用相同的代码来处理它们,而不是为几乎相同的项目设置两个不同的项目。
这两种类型的采购订单都来自一组抽象类,这些抽象类确定了两种PO类型共享的基本业务逻辑(数量、成本、PO编号等)。
基类
abstract class PO {
[XmlIgnore]
abstract POType PurchaseOrderType {get;}
[XmlIgnore]
abstract PO_Head Header {get;set;}
[XmlIgnore]
abstract List<PO_Line> LineItems {get;set;}
}
abstract class PO_Head {
[XmlIgnore]
abstract string PONumber {get;set;}
}
abstract class PO_Line {
[XmlIgnore]
abstract string ItemCode {get;set;}
[XmlIgnore]
abstract decimal UnitCost {get;set;}
[XmlIgnore]
abstract int OrderQty {get;set;}
}派生类
class POR : PO {
// POR implementations
}
class POR_Head : PO_Line {
// POR implementations
}
class POR_Line : PO_Line {
// POR implementations
}
class CPO : PO {
// CPO implementations
}
class CPO_Head : PO_Line {
// CPO implementations
}
class CPO_Line : PO_Line {
// CPO implementations
}然后在代码中使用基类抽象类来处理每个采购订单并将它们导入我们的会计系统。
for (int i = pending.Transactions.Count -1; i > -1; i--) {
PO pendingOrder = (PO)pending.Transactions[i];
// Import PO type
}问题是,当我尝试将每个派生类反序列化为每个适当的派生类时,它尝试将Header和LineItems反序列化为派生类型PO_Head和PO_Line。是否有任何方法可以显式地告诉XmlSerializer将Header和LineItems作为派生类版本-- CPO_Head和CPO_Line或POR_Head和POR_Line --这分别取决于被序列化的类-- CPO或POR。类似于下面的东西。
class CPO : PO {
[XmlIgnore]
override POType PurchaseOrderType => POType.CPO;
[XmlElement("CPO_Head")]
[XmlDeserializerType(typeof(CPO_Head))]
override PO_Head Header {get;set;}
[XmlArray("CPO_Lines")]
[XmlArrayItem("CPO_Line")]
[XmlDeserializerType(typeof(CPO_Line))]
override List<PO_Line> LineItems {get;set;}
}有点像用这个挖洞(第一次使用反序列化),所以我希望有一个简单的方法,可以省去我所做的大量工作!
提亚
编辑-用于根据请求反序列化/序列化的代码
public static void SerializeToXmlFile(object obj, FileInfo dstFile)
{
XmlSerializer xmlSerializer = new XmlSerializer(obj.GetType());
using (FileStream fs = dstFile.Open(FileMode.Create, FileAccess.Write))
{
xmlSerializer.Serialize(fs, obj);
}
}
public static object DeserializeFromXmlFile(FileInfo srcFile, Type type)
{
XmlSerializer xmlSerializer = new XmlSerializer(type);
using (FileStream fs = srcFile.Open(FileMode.Open, FileAccess.Read))
{
return xmlSerializer.Deserialize(fs);
}
}
public static void Main(string[] args)
{
// Deserialize from XML file
FileInfo srcFile = new FileInfo("path\to\file");
Type t;
if (srcFile.Name.Substring(0,3) == "CPO")
t = typeof(CPO);
else if (srcFile.Name.Substring(0,3) == "POR")
t = typeof(POR);
PO po = DeserializeFromXmlFile(file, t);
// Process the file
// ...
// Serialize back to file
FileInfo dstFile = new FileInfo("new\path\to\file");
SerializeToXmlFile(po, dstFile);
}编辑-固定
根据标记正确的答案,我能够通过在XmlElement和XmlArrayItem属性中指定XmlArrayItem来解决这个问题。
class POR {
[XmlElement(typeof(POR_Head), ElementName="PO_Head")]
override PO_Head Header {get;set;} = new POR_Head();
[XmlArray("PO_Lines")]
[XmlArrayItem(typeof(POR_Line), ElementName="PO_Line")]
override List<PO_Line> LineItems {get;set;} = new List<LineItems>();
}
class CPO {
[XmlElement(typeof(CPO_Head), ElementName="PO_Head")]
override PO_Head Header {get;set;} = new CPO_Head();
[XmlArray("PO_Lines")]
[XmlArrayItem(typeof(CPO_Line), ElementName="PO_Line")]
override List<PO_Line> LineItems {get;set;} = new List<LineItems>();
}发布于 2018-11-13 08:50:01
我想你是在找XmlArrayItemAttribute。根据医生的说法:
可以将XmlArrayItemAttribute应用于任何返回数组或提供对数组的访问的公共读/写成员。例如,返回对象数组、集合、ArrayList或实现IEnumerable接口的任何类的字段。 XmlArrayItemAttribute支持多态性--换句话说,它允许XmlSerializer向数组中添加派生对象。
如果我正确地理解了这个示例,那么应该使用序列化枚举中允许的可能派生类型的列表来编写该属性。
[XmlArrayItem (typeof(PO_Line), ElementName = "PO_Line"),
XmlArrayItem (typeof(CPO_Line),ElementName = "CPO_Line")]因为您只是传递一个字符串,所以属性将其解释为ElementName,而不是类型。必须使用typeof(ClassName)传递类型。
https://stackoverflow.com/questions/53266907
复制相似问题