【问题标题】:InvalidOperationException When XML Serializing Inherited ClassXML 序列化继承类时出现 InvalidOperationException
【发布时间】:2009-10-12 17:09:33
【问题描述】:

我在将 c# 类序列化为具有基类的 XML 文件时遇到问题...这是一个简单的示例:

namespace Domain
{
   [Serializable]
   public class ClassA
   {
      public virtual int MyProperty
      {
         get; set;
      }
   }
}

namespace Derived
{
   public class ClassA : Domain.ClassA
   {
      public override int MyProperty
      {
         get { return 1; } set { /* Do Nothing */ }
      }
   }
}

当我尝试序列化 Derived.ClassA 的实例时,我收到以下异常:

InvalidOperationException(类型“Domain.ClassA”和“Derived.ClassA”都使用命名空间中的 XML 类型名称“ClassA”。使用 XML 属性为该类型指定唯一的 XML 名称和/或命名空间。)

问题是我想创建一个简单地定义 XML 文件结构的基类,然后允许其他任何人从该类派生以插入业务规则,但格式将来自基.

这可能吗?如果可以,我如何赋予基类以允许这样做?

【问题讨论】:

  • 感谢您的意见。问题是,我很少提出问题,而且当我提出问题时,它们通常都非常棘手,而且我还没有得到对我提出的一个对我有帮助的问题的答案。那我该怎么办?
  • 这确实是一个棘手的情况......你应该接受答案 - 但如果你没有得到任何有用的答案,很难选择一个接受......我没有最终的答案....
  • 我同意...并不是我不想接受答案。同时,我不想仅仅说我已经接受了一个答案。我认为这违背了目的并改变了“接受”的含义。

标签: .net xml serialization


【解决方案1】:

这对我们有用。

[XmlType(TypeName = "DerivedClassA")] 

【讨论】:

    【解决方案2】:

    如果您可以随意将派生类重命名为与其基类不同的名称,您可以使用XmlAttributeOverrides 来执行此操作:

    // For ClassB, which derives from ClassA
    XmlAttributes          attributes  = new XmlAttributes();                        
    attributes.XmlRoot                 = new XmlRootAttribute("ClassA");
    
    XmlAttributeOverrides  overrides   = new XmlAttributeOverrides();
    overrides.Add(typeof(ClassB), attributes);
    
    XmlSerializer   serializer  = new XmlSerializer(typeof(ClassB), overrides);
    

    这将序列化为<ClassA> ... </ClassA>,并可以从该序列化为ClassB 实例。

    据我所知,当基类和派生类具有相同名称时(除了通过Data Contract Surrogates 或其他一些过度杀伤方法完全控制序列化过程之外),没有办法做到这一点。

    【讨论】:

    • 最终奏效的解决方案与此类似,但没有那么复杂。您是正确的,因为 .NET 类名必须不同……不幸的是,无论出于何种原因,都没有使用 .NET 命名空间。所以最简单的就是有一个简单版本的ClassABase,并将ClassA的XmlRoot属性附加到它,然后有一个名为ClassA的派生类。那时他们都连载相同。在不需要的地方将覆盖作为序列化程序的一部分。
    • 太棒了!但这适用于从 ClassABase 派生的 ClassB 吗?还是只需要一个子类?
    【解决方案3】:

    我认为您的派生类也需要用[Serializable] 属性标记才能可序列化/可反序列化。

    除了可序列化属性之外,您还需要使两者之一具有不同的 XML 名称 - 正如错误所说,在“XML 世界”中,它们都称为“ClassA”。其中一个必须以不同的方式命名,使用XmlElement 属性(假设您使用的是 XmlSerializer - 对吧?)

    namespace Domain
    {
       [Serializable]
       [XmlElement(ElementName="ClassABase")]
       public class ClassA
       {
          public virtual int MyProperty
          {
             get; set;
          }
       }
    }
    
    namespace Derived
    {
       [Serializable]
       public class ClassA : Domain.ClassA
       {
          public override int MyProperty
          {
             get { return 1; } set { /* Do Nothing */ }
          }
       }
    }
    

    马克

    【讨论】:

    • 试过了,但没有帮助。还有什么?
    【解决方案4】:

    为您的域设置基本命名空间并为派生类设置自定义元素名称:

    namespace Domain
    {
        [Serializable]
        [XmlRoot(Namespace = "http://mynamespace/domain/2009/")]
        public class ClassA
        {
            [XmlIgnore]
            public virtual int MyProperty { get; set; }
        }
    }
    
    namespace Derived
    {
        [Serializable]
        [XmlRoot(ElementName = "DerivedClassA")]
        public class ClassA : Domain.ClassA
        {
            public override int MyProperty
            {
                get
                {
                    return 1;
                }
                set
                {
                    base.MyProperty = value;
                }
            }
        }
    }
    

    【讨论】:

      【解决方案5】:

      我遇到了同样的问题,但有一个额外的限制:不能访问 Domain 或 Derived 类的源代码。继承自 Domain 对象的 Derived 对象,并且由于类具有相同的非限定名称,XmlSerializer 将无法序列化 Derived 类的对象。

      这可能可以通过蛮力解决(修改其中一个类的 IL 以添加适当的属性),但我想要一些“更干净”的东西。这是有效的:

      var attrs = new XmlAttributes();
      attrs.XmlType = new XmlTypeAttribute("anythingButClassA");
      
      var overrides = new XmlAttributeOverrides();
      overrides.Add(typeof(Domain.ClassA), attrs);
      
      var serializer = new XmlSerializer(typeof(Derived.ClassA), overrides);
      serializer.Serialize(Console.Out, new Derived.ClassA());
      

      即使您是域和/或派生类的作者,这样您也无需重命名它们。

      【讨论】:

        【解决方案6】:

        这只是提供信息,因为它没有提供具体的答案,但这里有一篇来自 2003 年 7 月 MSDN 问题的好文章,讨论了这些名称冲突。 "XML Namespace Collisions, XmlNodeList and Deserialization, and More".

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 2010-09-06
          • 1970-01-01
          • 1970-01-01
          • 2010-11-03
          • 2021-04-04
          • 2010-12-15
          • 1970-01-01
          • 2020-04-16
          相关资源
          最近更新 更多