C# XML序列化:反序列化抽象属性时出现问题
我仍在试图把我的头脑集中在整个xml序列化的事情上,似乎我再次需要一些帮助 我需要能够反序列化抽象类型的属性。随着时间的推移,此类型将添加许多不同的具体类型,并且在许多不同的模型中引用,因此显式列出每个具体类型并不是理想的解决方案 我已经阅读了这篇文章,并得出以下结论:C# XML序列化:反序列化抽象属性时出现问题,c#,.net,xml-serialization,C#,.net,Xml Serialization,我仍在试图把我的头脑集中在整个xml序列化的事情上,似乎我再次需要一些帮助 我需要能够反序列化抽象类型的属性。随着时间的推移,此类型将添加许多不同的具体类型,并且在许多不同的模型中引用,因此显式列出每个具体类型并不是理想的解决方案 我已经阅读了这篇文章,并得出以下结论: <Page> <introCommand> <PlayElement /> </introCommand> </Page> ** ** 命名空间测试服
<Page>
<introCommand>
<PlayElement />
</introCommand>
</Page>
**
**
命名空间测试服务
{
公共类XmlCommandSerializer:IXmlSerializable
{
//重写自XmlSerializer之后的隐式转换
//隐式转换到所需类型或从所需类型转换。
公共静态隐式运算符AbstractCommandModel(XmlCommandSerializer o)
{
返回o.数据;
}
公共静态隐式运算符XmlCommandSerializer(AbstractCommando模型)
{
返回o==null?null:新的XmlCommandSerializer(o);
}
私有抽象模型数据;
///
///[具体]要存储的数据/存储为XML。
///
公共抽象模型数据
{
获取{return_data;}
设置{u data=value;}
}
///
///**不要使用**这只是为了启用XML序列化而添加的。
///
///不要使用此构造函数
公共XmlCommandSerializer()
{
//默认Ctor(Xml序列化所需-不使用)
}
///
///初始化序列化程序以使用给定数据。
///
///指定的AbstractCommandModel的具体对象。
公共XmlCommandSerializer(AbstractCommandModel数据)
{
_数据=数据;
}
#区域IXmlSerializable成员
public System.Xml.Schema.XmlSchema GetSchema()
{
return null;//由于架构未知,因此这没有问题。
}
public void ReadXml(System.Xml.XmlReader)
{
//从抽象类型强制转换回数据。
字符串typeAttrib=reader.GetAttribute(“类型”);
//确保已指定类型
if(typeAttrib==null)
抛出新ArgumentNullException(“无法读取抽象类型的Xml数据””+typeof(AbstractCommandModel)。Name+
“,因为XML中没有指定“type”属性。”);
Type Type=Type.GetType(typeAttrib);
//检查是否找到类型。
if(type==null)
抛出新的InvalidCastException(“无法读取抽象类型的Xml数据””+typeof(AbstractCommandModel)。Name+
“'因为找不到XML中指定的类型。“);
//检查类型是否为AbstractCommandModel的子类。
if(!type.IsSubclassOf(typeof(AbstractCommandModel)))
抛出新的InvalidCastException(“无法读取抽象类型的Xml数据””+typeof(AbstractCommandModel)。Name+
“,因为XML中指定的类型不同(“+Type.Name+”)”);
//读取数据,根据(现在已知的)具体类型进行反序列化。
reader.ReadStartElement();
this.Data=(AbstractCommandModel)新建
XmlSerializer(类型)。反序列化(读取器);
reader.ReadEndElement();
}
public void WriteXml(System.Xml.XmlWriter)
{
//将类型名作为Attrib写入XML元素并序列化
类型类型=_data.GetType();
//错误修复:程序集必须是FQN,因为类型可以/是当前的外部类型。
WriteAttributeString(“类型”,类型.AssemblyQualifiedName);
新的XmlSerializer(类型).Serialize(写入程序,_数据);
}
#端区
}
}
然而,当我运行反序列化程序时,我得到一个InvalidOperationException,声明“XML文档(3,3)中有一个错误”。与前面提到的线程中的示例相比,我唯一改变的是类名
我做得对吗?如果是,是什么导致了这个错误?来自您的示例:
//[XmlElement(typeof(PlayElement))] **NOTE: the example works if I use this instead
这是支持抽象类的推荐方法。您可以按元素名称切换实例,并使用如下多个声明:
[XmlElement("playElement", typeof(PlayElement))]
[XmlElement("testElement", typeof(TestElement))]
public AbstractCommandModel Command;
当然,您仍然需要删除“introCommand”元素或添加另一个类来嵌套上述声明
如果您仍然需要手动执行序列化,那么您的路径是正确的。我想,您的示例运行得很好,下面是XML输出:
<Page>
<introCommand type="TestService.PlayElement, TestService, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null">
<PlayElement />
</introCommand>
</Page>
从你的例子来看:
//[XmlElement(typeof(PlayElement))] **NOTE: the example works if I use this instead
这是支持抽象类的推荐方法。您可以按元素名称切换实例,并使用如下多个声明:
[XmlElement("playElement", typeof(PlayElement))]
[XmlElement("testElement", typeof(TestElement))]
public AbstractCommandModel Command;
当然,您仍然需要删除“introCommand”元素或添加另一个类来嵌套上述声明
如果您仍然需要手动执行序列化,那么您的路径是正确的。我想,您的示例运行得很好,下面是XML输出:
<Page>
<introCommand type="TestService.PlayElement, TestService, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null">
<PlayElement />
</introCommand>
</Page>
这就是为什么我很久以前放弃了XamlServices的XmlSerializer和NetDataContractSerializer。@XamlServices看起来会更接近我所需要的吗。实际上,整个目的是从XML结构构造复杂的对象图。缺点是这需要对XML进行大量重构才能工作。这不是不可能的,但也不完全理想。我得再仔细研究一下,我明白这是怎么回事。但很高兴知道,在未来,XmlSerializer还有许多新的替代品。这就是为什么我很久以前放弃了XmlSerializer用于XamlServices和NetDataContractSerializer的原因。@XamlServices看起来会更接近我的需要吗。事实上,整个目的是为了
<Page>
<introCommand type="TestService.PlayElement, TestService, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null">
<PlayElement />
</introCommand>
</Page>
private static void Main()
{
StringWriter dataOut = new StringWriter();
XmlTextWriter writer = new XmlTextWriter(dataOut);
writer.Formatting = Formatting.Indented;
Page p = new Page();
p.introCommand = new PlayElement();
new XmlSerializer(typeof(Page)).Serialize(writer, p);
string xml = dataOut.ToString();
Console.WriteLine(xml);
XmlTextReader reader = new XmlTextReader(new StringReader(xml));
Page copy = (Page) new XmlSerializer(typeof (Page)).Deserialize(reader);
}