.NET中的XML序列化允许多态对象通过XmlSerializer构造函数的extraTypes[]参数。它还允许为实现IXmlSerializable的类型定制XML序列化。
但是,我无法将这两个特性结合起来--如下面这个最小的示例所示:
using System;
using System.IO;
using System.Xml;
using System.Xml.Schema;
using System.Xml.Serialization;
namespace CsFoo
{
public class CustomSerializable : IXmlSerializable
{
public XmlSchema GetSchema() { return null; }
public void ReadXml(XmlReader xr) { }
public void WriteXml(XmlWriter xw) { }
}
class CsFoo
{
static void Main()
{
XmlSerializer xs = new XmlSerializer(
typeof(object),
new Type[] { typeof(CustomSerializable) });
xs.Serialize(new StringWriter(), new CustomSerializable());
}
}最后一行向System.InvalidOperationException抛出以下消息:
不能在此上下文中使用CsFoo.CustomSerializable类型来使用CsFoo.CustomSerializable作为参数、返回类型或类或结构的成员,必须将参数、返回类型或成员声明为CsFoo.CustomSerializable类型(不能是对象)。不能在非类型集合(如CsFoo.CustomSerializable )中使用类型为ArrayLists的对象.
通过遍历动态生成的XML程序集,我们最终通过调用以下命令返回到.NET标准库代码:
System.Xml.Serialization.XmlSerializationWriter.WriteTypedPrimitive(
String, String, Object, Boolean) : Void反过来,这又导致:
protected Exception CreateUnknownTypeException(Type type)
{
if (typeof(IXmlSerializable).IsAssignableFrom(type))
{
return new InvalidOperationException(
Res.GetString("XmlInvalidSerializable",
new object[] { type.FullName }));
}
// Rest omitted...反射器显示XmlInvalidSerializable资源对应于上面的字符串--也就是说,WriteTypedPrimitive不喜欢IXmlSerializable。
如果我们生成一个非多态序列化程序,如下所示:
XmlSerializer xs = new XmlSerializer(typeof(CustomSerializable));.NET将生成一个调用:
System.Xml.Serialization.XmlSerializationWriter.WriteSerializable(
IXmlSerializable, String, String, Boolean) : Void 这正确地处理了IXmlSerializable。有人知道为什么.NET在多态情况下不使用这个函数吗?看看XML序列化程序生成的C#,在我看来,这是非常容易做到的。下面是我从XML序列化程序获得的一些代码,还有一个未经测试的解决方案:
void Write1_Object(string n, string ns, global::System.Object o,
bool isNullable, bool needType)
{
if ((object)o == null)
{
if (isNullable) WriteNullTagLiteral(n, ns);
return;
}
if (!needType)
{
System.Type t = o.GetType();
if (t == typeof(global::System.Object))
{
}
>>> patch begin <<<
+ else if (typeof(IXmlSerializable).IsAssignableFrom(t))
+ {
+ WriteSerializable((System.Xml.Serialization.IXmlSerializable)
((global::CsFoo.CustomSerializable)o),
+ @"CustomSerializable", @"", true, true);
+ }
>>> patch end <<<
else
{
WriteTypedPrimitive(n, ns, o, true);
return;
}
}
WriteStartElement(n, ns, o, false, null);
WriteEndElement(o);
}这是由于技术原因还是仅仅是一个功能限制而被忽略了?不支持的特征,还是我的白痴?我的内线谷歌技术让我失望了。
我在这里确实发现了一些相关的问题,其中"C# Xml-使用IXmlSerializable序列化派生类“是最相关的。这让我相信这是不可能的。
在这种情况下,我当前的想法是在根基类中注入一个默认的IXmlSerializable实现。然后一切都会变成IXmlSerializable,.NET也不会抱怨。我可以使用Reflection.Emit为每种具体类型提取ReadXml和WriteXml主体,生成与使用库类型相同的XML。
有些人在遇到XML序列化问题时会想:“我知道,我将使用Reflection.Emit生成代码。”现在他们有两个问题。
注意:我知道.NET的XML序列化的替代方案,并且知道它有局限性。我也知道保存POCO比处理抽象数据类型要简单得多。但是我有一堆遗留代码,需要对现有XML模式的支持。
因此,虽然我很感激在SomeOtherXML、YAML、XAML、ProtocolBuffers、DataContract、RandomJsonLibrary、Thrift或your MorseCodeBasedSerializeToMp3库中显示这是多么简单的回复--嘿,我可能会学到-,但我希望的是一个XML序列化器的工作--如果不是解决方案。
发布于 2009-07-28 03:18:59
当使用object时,我能够重现您的问题。
XmlSerializer xs = new XmlSerializer(
typeof(object),
new Type[] { typeof(CustomSerializable) });但是,我随后创建了一个派生的CustomSerializable类
public class CustomSerializableDerived : CustomSerializable
{
}并试图将其序列化:
XmlSerializer xs = new XmlSerializer(
typeof(CustomSerializable),
new Type[] { typeof(CustomSerializableDerived) });这个成功了。
因此,问题似乎仅限于将"object“指定为要序列化的类型的情况,但如果指定了具体的基本类型,则不适用。
明早我会再做些研究。
发布于 2011-05-13 23:21:23
首先,海报声明
.NET中的XML序列化允许多态对象通过XmlSerializer构造函数的extraTypes[]参数。
有误导性。根据MSDN,外型用于:
如果属性或字段返回数组,则extraTypes参数指定可以插入到数组中的对象。
这意味着,如果序列化对象图中的某个位置通过数组返回多态对象,则可以对它们进行处理。
虽然我还没有真正找到如何将多态类型序列化为根XML对象的解决方案,但我能够使用标准的XML序列化程序或IXmlSerializable来序列化对象图中的多态类型。以下是我的解决方案:
using System.IO;
using System.Xml;
using System.Xml.Schema;
using System.Xml.Serialization;
namespace CsFoo
{
public class Foo
{
[XmlElement("BarStandard", typeof(BarStandardSerializable))]
[XmlElement("BarCustom", typeof(BarCustomSerializable))]
public Bar BarProperty { get; set; }
}
public abstract class Bar
{ }
public class BarStandardSerializable : Bar
{ }
public class BarCustomSerializable : Bar, IXmlSerializable
{
public XmlSchema GetSchema() { return null; }
public void ReadXml(XmlReader xr) { }
public void WriteXml(XmlWriter xw) { }
}
class CsFoo
{
static void Main()
{
StringWriter sw = new StringWriter();
Foo f1 = new Foo() { BarProperty = new BarCustomSerializable() };
XmlSerializer xs = new XmlSerializer(typeof(Foo));
xs.Serialize(sw, f1);
StringReader sr= new StringReader(sw.ToString());
Foo f2 = (Foo)xs.Deserialize(sr);
}
}
}请注意,使用任何一个
XmlSerializer xs = new XmlSerializer(typeof(Foo),
new Type[] { typeof(BarStandardSerializable),
typeof(BarCustomSerializable)});或
[XmlInclude(typeof(BarCustomSerializable))]
[XmlInclude(typeof(BarStandardSerializable))]
public abstract class Bar
{ }如果没有定义XmlElement,将导致代码在序列化时失败。
发布于 2009-07-29 01:09:14
为了使IxmlSerializable工作,类需要一个空构造函数。
考虑基类
https://stackoverflow.com/questions/631852
复制相似问题