首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >多态类型与IXmlSerializable

多态类型与IXmlSerializable
EN

Stack Overflow用户
提问于 2009-03-10 19:18:04
回答 3查看 4.6K关注 0票数 9

.NET中的XML序列化允许多态对象通过XmlSerializer构造函数的extraTypes[]参数。它还允许为实现IXmlSerializable的类型定制XML序列化。

但是,我无法将这两个特性结合起来--如下面这个最小的示例所示:

代码语言:javascript
复制
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标准库代码:

代码语言:javascript
复制
System.Xml.Serialization.XmlSerializationWriter.WriteTypedPrimitive(
     String, String, Object, Boolean) : Void

反过来,这又导致:

代码语言:javascript
复制
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

如果我们生成一个非多态序列化程序,如下所示:

代码语言:javascript
复制
XmlSerializer xs = new XmlSerializer(typeof(CustomSerializable));

.NET将生成一个调用:

代码语言:javascript
复制
System.Xml.Serialization.XmlSerializationWriter.WriteSerializable(
    IXmlSerializable, String, String, Boolean) : Void 

这正确地处理了IXmlSerializable。有人知道为什么.NET在多态情况下不使用这个函数吗?看看XML序列化程序生成的C#,在我看来,这是非常容易做到的。下面是我从XML序列化程序获得的一些代码,还有一个未经测试的解决方案:

代码语言:javascript
复制
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为每种具体类型提取ReadXmlWriteXml主体,生成与使用库类型相同的XML。

有些人在遇到XML序列化问题时会想:“我知道,我将使用Reflection.Emit生成代码。”现在他们有两个问题。

注意:我知道.NET的XML序列化的替代方案,并且知道它有局限性。我也知道保存POCO比处理抽象数据类型要简单得多。但是我有一堆遗留代码,需要对现有XML模式的支持。

因此,虽然我很感激在SomeOtherXMLYAMLXAMLProtocolBuffersDataContractRandomJsonLibraryThrift或your MorseCodeBasedSerializeToMp3库中显示这是多么简单的回复--嘿,我可能会学到-,但我希望的是一个XML序列化器的工作--如果不是解决方案。

EN

回答 3

Stack Overflow用户

发布于 2009-07-28 03:18:59

当使用object时,我能够重现您的问题。

代码语言:javascript
复制
XmlSerializer xs = new XmlSerializer(
    typeof(object),
    new Type[] { typeof(CustomSerializable) });

但是,我随后创建了一个派生的CustomSerializable

代码语言:javascript
复制
public class CustomSerializableDerived : CustomSerializable
{
}

并试图将其序列化:

代码语言:javascript
复制
XmlSerializer xs = new XmlSerializer(
    typeof(CustomSerializable),
    new Type[] { typeof(CustomSerializableDerived) });

这个成功了。

因此,问题似乎仅限于将"object“指定为要序列化的类型的情况,但如果指定了具体的基本类型,则不适用。

明早我会再做些研究。

票数 2
EN

Stack Overflow用户

发布于 2011-05-13 23:21:23

首先,海报声明

.NET中的XML序列化允许多态对象通过XmlSerializer构造函数的extraTypes[]参数。

有误导性。根据MSDN,外型用于:

如果属性字段返回数组,则extraTypes参数指定可以插入到数组中的对象。

这意味着,如果序列化对象图中的某个位置通过数组返回多态对象,则可以对它们进行处理。

虽然我还没有真正找到如何将多态类型序列化为根XML对象的解决方案,但我能够使用标准的XML序列化程序或IXmlSerializable来序列化对象图中的多态类型。以下是我的解决方案:

代码语言:javascript
复制
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);
    }
  }
}

请注意,使用任何一个

代码语言:javascript
复制
XmlSerializer xs = new XmlSerializer(typeof(Foo), 
            new Type[] { typeof(BarStandardSerializable),
            typeof(BarCustomSerializable)});

代码语言:javascript
复制
[XmlInclude(typeof(BarCustomSerializable))]
[XmlInclude(typeof(BarStandardSerializable))]
public abstract class Bar
{ }

如果没有定义XmlElement,将导致代码在序列化时失败。

票数 1
EN

Stack Overflow用户

发布于 2009-07-29 01:09:14

为了使IxmlSerializable工作,类需要一个空构造函数。

考虑基类

  • MyBaseXmlClass:IXmlSerializable --实施GetSchema
  • MyXmlClass:MyBaseXmlClass -- ReadXml
    • WriteXml

票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/631852

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档