我有一个对象,我正在尝试序列化为XML。在此对象内部是泛型类型(抽象类)的列表。此列表中的每个项可以是不同的类,但所有项都继承自抽象基类:
public abstract class animal
{
public string type { get; set; }
}
public class cat:animal
{
public string size { get; set; }
public string furColor { get; set; }
}
public class fish:animal
{
public string size { get; set; }
public string scaleColor { get; set; }
}
当我序列化列表时,我希望它看起来像这样:
<animal type="cat">
<size>medium</size>
<furColor>black</furColor>
</animal>
<animal type="fish">
<size>small</size>
<scaleColor>silver</scaleColor>
</animal>
我尝试过这个简单的解决方案:
[XmlElement("Animal")]
public List<animal> Animals { get; set; }
但它会抛出错误,因为它不期望对象类型为“cat”。将[XmlInclude]标记添加到基类,派生类或整个包含类(让我们称之为动物园)对此没有帮助。
我可以将typeof指定用于单个类:
[XmlElement("Animal", typeof(cat))]
public List<animal> Animals { get; set; }
只要我只使用猫,这就可以正常使用。再一次,我在混合物中添加一条鱼,它会以相同的错误(不期待鱼)爆炸。
我可以添加多个typeof属性:
[XmlElement("Animal")]
[XmlElementAttribute(typeof(cat))]
[XmlElementAttribute(typeof(fish))]
public List<animal> Animals { get; set; }
并且这会编译,但会忽略元素名称,并将对象序列化为<cat> </cat>
和<fish> </fish>
,这是不可接受的。
我甚至尝试添加多个[XmlElement]标签:
[XmlElement("Animal", typeof(cat))]
[XmlElement("Animal", typeof(fish))]
public List<animal> Animals { get; set; }
这个引发了一个不同的例外,这次对象“cat”和“fish”都在同一范围内使用“Animal”类型。
有人能想出解决方法吗?
UPDATE 经过一番挖掘后,我发现This SO post建议将命名空间添加到基类:
[XmlRoot(Namespace="myNamespace")]
[XmlInclude(typeof(cat))]
[XmlInclude(typeof(fish))]
public abstract class animal
序列化产生以下结果:
<animal xsi:type="cat" type="cat">
...
</animal>
<animal xsi:type="fish" type="fish">
...
</animal>
其中 xsi:type =“cat”是指类的名称, type =“cat”是指在基类中创建的type属性(看到最顶层的例子)。这是如此接近我所需要的,我担心我可能只是在这里缺乏经验,但有没有办法摆脱xsi:type属性列表?
答案 0 :(得分:3)
将XmlInclude属性添加到基类应解决此序列化问题
[Serializable]
[XmlInclude(typeof(cat))]
[XmlInclude(typeof(fish))]
class animals
{
....
}
public class cat:animals
{
public string size { get; set; }
public string furColor { get; set; }
}
public class fish:animals
{
public string size { get; set; }
public string scaleColor { get; set; }
}
更新
这是一个适用于我的简短示例,您实际上并不需要type属性,因为您可以使用typeof()方法检索它。除非type属性有另一个目的。
List<animal> animals = new List<animal>();
cat catofdoom = new cat();
catofdoom.furColor = "brown";
catofdoom.size = "10 pounds";
animals.Add(catofdoom);
fish fishofdoom = new fish();
fishofdoom.scaleColor = "blue";
fishofdoom.size = "12 inches";
animals.Add(fishofdoom);
try
{
XmlSerializer xs = new XmlSerializer(typeof(List<animal>));
using (StreamWriter wr = new StreamWriter("animal.xml"))
{
xs.Serialize(wr, animals);
}
}
catch (Exception e)
{
throw;
}
结果(非常基本的序列化,没有选项):
<?xml version="1.0" encoding="utf-8"?>
<ArrayOfAnimal xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<animal xsi:type="cat">
<size>10 pounds</size>
<furColor>brown</furColor>
</animal>
<animal xsi:type="fish">
<size>12 inches</size>
<scaleColor>blue</scaleColor>
</animal>
</ArrayOfAnimal>
答案 1 :(得分:2)
你需要两个!
[Serializable]
[XmlInclude(typeof(cat))]
[XmlInclude(typeof(fish))]
class animals
{
....
}
public class cat:animals
{
public string size { get; set; }
public string furColor { get; set; }
}
public class fish:animals
{
public string size { get; set; }
public string scaleColor { get; set; }
}
请注意XmlElement
名称的细微更改。这将正常工作。
[XmlElement("cat", typeof(cat))]
[XmlElement("fish", typeof(fish))]
public List<animal> Animals { get; set; }
答案 2 :(得分:1)
我建议使用DataContractSerializer并将已知类型包含在序列化程序中。使用XmlInclude是encasulation原则的中断。 有关某些样本,请参阅提供的MSDN链接...