C# 如何使用XmlSerializer序列化派生实例?
我意识到这看起来是一个完全相同的问题,但我不知道如何按照同一个问题的指导来实现这一点:C# 如何使用XmlSerializer序列化派生实例?,c#,xmlserializer,derived-class,C#,Xmlserializer,Derived Class,我意识到这看起来是一个完全相同的问题,但我不知道如何按照同一个问题的指导来实现这一点: using System; using System.Text; using System.Xml; using System.Xml.Schema; using System.Xml.Serialization; namespace xmlSerializerLab { public class Utf8StringWriter : System.IO.StringWriter {
using System;
using System.Text;
using System.Xml;
using System.Xml.Schema;
using System.Xml.Serialization;
namespace xmlSerializerLab
{
public class Utf8StringWriter : System.IO.StringWriter
{
public override Encoding Encoding => Encoding.UTF8;
}
[XmlRoot(ElementName = "Query", Namespace = "http://www.opengis.net/wfs")]
public class Query
{
[XmlElement(ElementName = "Filter", Namespace = "http://www.opengis.net/ogc")]
public Filter Filter { get; set; }
}
[XmlInclude(typeof(PropertyIsOpFilter))]
[XmlInclude(typeof(PropertyIsEqualToFilter))]
[XmlInclude(typeof(OpFilterBase))]
[XmlInclude(typeof(LiteralFilter))]
[XmlInclude(typeof(Query))]
[Serializable]
public class Filter
{
[XmlElement]
public Filter And { get; set; }
}
public class PropertyIsOpFilter : Filter, IXmlSerializable
{
public Filter LeftOp { get; set; }
public Filter RightOp { get; set; }
public XmlSchema GetSchema()
{
return null;
}
public void ReadXml(XmlReader reader) { }
public void WriteXml(XmlWriter writer)
{
Program.ToXml(LeftOp, writer);
Program.ToXml(RightOp, writer);
}
}
[XmlRoot("IsEqualTo")]
public class PropertyIsEqualToFilter : PropertyIsOpFilter { }
public class OpFilterBase : Filter, IXmlSerializable
{
public string Op { get; set; }
public object Value { get; set; }
public XmlSchema GetSchema()
{
return null;
}
public void ReadXml(XmlReader reader) { }
public void WriteXml(XmlWriter writer)
{
if (!String.IsNullOrEmpty(Op))
{
writer.WriteStartElement(Op);
writer.WriteValue(Value);
writer.WriteEndElement();
}
else
{
writer.WriteValue(Value);
}
}
}
public class LiteralFilter : OpFilterBase { }
class Program
{
public static void ToXml(Object o, XmlWriter writer)
{
var inputSerializer = new XmlSerializer(o.GetType(), new Type[] {
typeof(Filter),
typeof(PropertyIsOpFilter),
typeof(PropertyIsEqualToFilter),
typeof(OpFilterBase),
typeof(LiteralFilter),
typeof(Query)
});
inputSerializer.Serialize(writer, o);
}
public static string ToXml(Object o)
{
var inputSerializer = new XmlSerializer(o.GetType());
using (var writer = new Utf8StringWriter())
{
using (var xmlWriter = new XmlTextWriter(writer))
{
ToXml(o, xmlWriter);
}
return writer.ToString();
}
}
static void Main(string[] args)
{
Filter o = new PropertyIsEqualToFilter()
{
LeftOp = new LiteralFilter()
{
Value = 1
},
RightOp = new LiteralFilter()
{
Value = 1
}
};
var query = new Query()
{
Filter = o
};
Console.WriteLine(ToXml(query));
Console.ReadLine();
}
}
}
它会导致以下异常:
InvalidOperationException:类型
xmlSerializerLab.PropertyIsEqualToFilter不能在此过程中使用
上下文将xmlSerializerLab.PropertyIsEqualToFilter用作
参数、返回类型或类或结构的成员,
返回类型,或必须将成员声明为类型
xmlSerializerLab.PropertyIsEqualToFilter(不能是对象)。
xmlSerializerLab.PropertyIsEqualToFilter类型的对象可能不可用
用于非类型集合,如ArrayList
据我所知,我需要在PropertyOpfilter和OpFilterBase上使用IXmlSerializable,因为我正试图以所描述的特定XML格式为目标。但是我发现我还必须使查询类IXmlSerializable
下面是一个示例XML文档,我希望能够从模型中生成该文档:
<GetFeature xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema"
service="WFS"
version="1.1.0"
maxFeatures="0" xmlns="http://www.opengis.net/wfs">
<ResultType>Results</ResultType>
<OutputFormat>text/gml; subtype=gml/3.1.1</OutputFormat>
<Query
d2p1:srsName="EPSG:4326" xmlns:d2p1="http://www.opengis.net/ogc">
<d2p1:Filter>
<d2p1:IsEqualTo>
<d2p1:PropertyName>Prop1</d2p1:PropertyName>
<d2p1:Literal>1</d2p1:Literal>
</d2p1:IsEqualTo>
</d2p1:Filter>
</Query>
</GetFeature>
结果
text/gml;子类型=gml/3.1.1
建议1
1.
通过使查询类IXmlSerializable并编写一些好的WriteXml和ReadXml逻辑,我可以让它工作,但我希望它能够工作,而不必做所有这些,因为XmlRoot、XmlAttribute和XmlElement标记应该为序列化程序提供足够的信息,让它知道根据标记名实例化哪个类(匹配ElementName)以及如何基于属性进行序列化。您看到的问题可以通过以下最小示例重现:
public class BaseClass
{
}
public class DerivedClass : BaseClass, IXmlSerializable
{
#region IXmlSerializable Members
public XmlSchema GetSchema() { return null; }
public void ReadXml(XmlReader reader) { throw new NotImplementedException(); }
public void WriteXml(XmlWriter writer) { }
#endregion
}
使用序列化代码:
BaseClass baseClass = new DerivedClass();
using (var textWriter = new StringWriter())
{
using (var xmlWriter = XmlWriter.Create(textWriter))
{
var serializer = new XmlSerializer(typeof(BaseClass), new Type[] { typeof(DerivedClass) });
serializer.Serialize(xmlWriter, baseClass);
}
Console.WriteLine(textWriter.ToString());
}
将引发以下异常(示例):
这是我在XmlSerializer
中看到的最没有帮助的异常消息之一。要了解异常,您需要了解XmlSerializer
如何通过处理多态性。如果我从DerivedClass
中删除IXmlSerializable
,将生成以下XML():
注:
- 要使
机制工作,所有包含的类型显然必须与基类型位于同一个XML命名空间中。为了确保这一点,我将[xmlclude]
添加到所有[XmlRoot(namespace=XmlNamespaces.OpengisWfs)]
子类型中过滤器
属性可以添加到其直接父类型或最低公共基类型。在上面的代码中,我将属性添加到直接父类型,以便成功序列化中间类型的成员,例如:[xmlclude(typeof(DerivedType))]
public class SomeClass { PropertyIsOpFilter IsOpFilter { get; set; } }
- 如果使用
构造函数,则必须静态缓存序列化程序,以避免严重的内存泄漏,如前所述。这在我的解决方案中不是必需的,但在您的问题中使用它新的XmlSerializer(Type,Type[])
<Query xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://www.opengis.net/wfs">
<Filter xsi:type="PropertyIsEqualToFilter">
<LeftOp xsi:type="LiteralFilter">
<Value xsi:type="xsd:int">1</Value>
</LeftOp>
<RightOp xsi:type="LiteralFilter">
<Value xsi:type="xsd:int">1</Value>
</RightOp>
</Filter>
</Query>
1.
1.
回答得很好!我的两位同事提供了相同的解决方案,但没有说得这么清楚!但我无权更改XML格式。我正在尝试生成与OGC WFS兼容的XML。这里可以找到一个更复杂的示例:。我将更新问题,以包含此重要约束。根据您的分析是的,XmlInclude似乎不在讨论范围内。@CoreyAlix-也许你需要问第二个问题。你回答了我的明确问题(是的,可以做到)和我的隐含问题(不,我无法通过编写IXmlSerializable类获得我要找的XML)@CoreyAlix-实际上,您可能可以使用而不是xmlclude
。但是我们需要查看所需的XML,而不是所需的类,这就是为什么我建议您问另一个问题。
public static class XmlNamespaces
{
public const string OpengisWfs = "http://www.opengis.net/wfs";
}
[XmlRoot(Namespace = XmlNamespaces.OpengisWfs)]
public class Query
{
public Filter Filter { get; set; }
}
[XmlInclude(typeof(PropertyIsOpFilter))]
[XmlInclude(typeof(OpFilterBase))]
[XmlRoot(Namespace = XmlNamespaces.OpengisWfs)]
public class Filter
{
[XmlElement]
public Filter And { get; set; }
}
[XmlInclude(typeof(PropertyIsEqualToFilter))]
[XmlRoot(Namespace = XmlNamespaces.OpengisWfs)]
public class PropertyIsOpFilter : Filter
{
public Filter LeftOp { get; set; }
public Filter RightOp { get; set; }
}
[XmlRoot("IsEqualTo", Namespace = XmlNamespaces.OpengisWfs)]
public class PropertyIsEqualToFilter : PropertyIsOpFilter { }
[XmlInclude(typeof(LiteralFilter))]
[XmlRoot(Namespace = XmlNamespaces.OpengisWfs)]
public class OpFilterBase : Filter
{
public string Op { get; set; }
public object Value { get; set; }
}
[XmlRoot(Namespace = XmlNamespaces.OpengisWfs)]
public class LiteralFilter : OpFilterBase { }
public class SomeClass
{
PropertyIsOpFilter IsOpFilter { get; set; }
}
<Query xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://www.opengis.net/wfs">
<Filter xsi:type="PropertyIsEqualToFilter">
<LeftOp xsi:type="LiteralFilter">
<Value xsi:type="xsd:int">1</Value>
</LeftOp>
<RightOp xsi:type="LiteralFilter">
<Value xsi:type="xsd:int">1</Value>
</RightOp>
</Filter>
</Query>