我得到了一个例外
The type KML.Placemark was not expected. Use the XmlInclude or SoapInclude attribute to specify types that are not known statically.
当我尝试序列化我的对象时。我知道这个例外有两种不同的解决方案,但在这种情况下都不起作用。
某些背景:
我有一个严格遵循GoogleEarth / OpenGIS KML format的类结构(用于在GoogleEarth上绘图)。
我的根类型为KMLDocument
,其中包含一组KMLObjects
:
public class KMLDocument
{
public KMLObject[] members;
}
KMLObject
是Feature
的基本类型,Placemark
问题:
当我为KMLDocument构造序列化程序时,它不会直接知道像Placemark
这样的派生类型,除非我明确告诉它。所以我这样做:
XmlSerializer serializer = new XmlSerializer(typeof(KMLDocument),
new Type[] { typeof(KMLObject),
typeof(Feature),
typeof(Placemark) } );
我还将属性附加到KMLDocument
类,以确保它知道所有重要类型:
[XmlRootAttribute("kml", Namespace="http://www.opengis.net/kml/2.2")]
[XmlInclude(typeof(KMLObject))]
[XmlInclude(typeof(Feature))]
[XmlInclude(typeof(Placemark))]
public class KMLDocument
{ .... }
但是,尽管我打电话时告诉序列化器有两种不同的方式Placemark
序列化,我得到例外:
static void Main(string[] args)
{
KMLDocument kml = new KMLDocument();
kml.AddPlacemark("MyPlacemark", "MyTest");
XmlSerializer serializer = new XmlSerializer(typeof(KMLDocument),
new Type[] { typeof(KMLObject),
typeof(Feature),
typeof(Placemark) } );
serializer.Serialize(new StreamWriter("MyKML.kml"), kml); // Exception on this line!
}
如果我添加一个类型为Placemark的虚拟变量,突然序列化程序可以找到该类型,并且它可以正常工作:
public class KMLDocument
{
public KMLObject[] members;
public Placemark dummy_var; // Should NOT be needed!
}
我错过了什么?为什么两者我的XmlSerializer-Constructor和我的属性未能提供重要信息?
答案 0 :(得分:3)
地标和要素是KMLObject的子类。 members
字段包含地标和要素的混合数组。
members
字段必须用XmlArrayItemAttribute标记,以指定它包含的元素是多态的。
http://msdn.microsoft.com/en-us/library/system.xml.serialization.xmlarrayitemattribute.aspx
答案 1 :(得分:0)
假设我正确地阅读此内容KMLObject
是Feature
和Placemark
继承的基础对象。 AddPlacemark()
创建Placemark
个实例,并将其添加到members
数组中。
这应该有助于
public class KMLDocument
{
[XmlElement("Placemark", Type=typeof(Placemark)),
XmlElement("Feature", Type=typeof(Feature))]
public KMLObject[] members;
}
您不应该需要添加到序列化程序或文档中的任何缩写。我还要将members
声明为List<KMLObject>
而不是数组。
答案 2 :(得分:0)
public class KMLDocument
{
public List<KMLObject> members = new List<KMLObject>();
public void AddPlacemark(string p, string v)
{
members.Add(new Placemark(p, v));
}
public void AddFeature()
{
members.Add(new Feature());
}
}
public class KMLObject { }
public class Feature : KMLObject { }
public class Placemark : Feature
{
public string p;
public string v;
public Placemark() { }
public Placemark(string p1, string v1) { p = p1; v = v1; }
}
然后我用以下内容运行它:
KMLDocument kml = new KMLDocument();
kml.AddFeature();
kml.AddPlacemark("MyPlacemark", "MyTest");
XmlSerializer serializer = new XmlSerializer(typeof(KMLDocument),
new Type[] { typeof(KMLObject),
typeof(Feature),
typeof(Placemark) });
serializer.Serialize(new StreamWriter("MyKML.kml"), kml);
然后它会生成以下内容:
<?xml version="1.0" encoding="utf-8"?>
<KMLDocument ...>
<members>
<KMLObject xsi:type="Feature" />
<KMLObject xsi:type="Placemark">
<p>MyPlacemark</p>
<v>MyTest</v>
</KMLObject>
</members>
</KMLDocument>
<强>更新强> 您可以使用XmlAttributeOverrides强制XML创建Feature或Placemark值而不是KMLObject。下面是使用我上面的代码序列化的样子。
XmlAttributes attrs = new XmlAttributes();
XmlElementAttribute attr = new XmlElementAttribute();
attr.ElementName = "Feature";
attr.Type = typeof(Feature);
attrs.XmlElements.Add(attr);
XmlElementAttribute attr2 = new XmlElementAttribute();
attr2.ElementName = "Placemark";
attr2.Type = typeof(Placemark);
attrs.XmlElements.Add(attr2);
XmlAttributeOverrides attrOverrides = new XmlAttributeOverrides();
attrOverrides.Add(typeof(KMLDocument), "members", attrs);
KMLDocument kml = new KMLDocument();
kml.AddFeature();
kml.AddPlacemark("MyPlacemark", "MyTest");
XmlSerializer serializer = new XmlSerializer(typeof(KMLDocument),
attrOverrides);
serializer.Serialize(new StreamWriter("MyKML2.kml"), kml);
这将生成以下XML输出:
<?xml version="1.0" encoding="utf-8"?>
<KMLDocument ...>
<Feature />
<Placemark>
<p>MyPlacemark</p>
<v>MyTest</v>
</Placemark>
</KMLDocument>