代码之家  ›  专栏  ›  技术社区  ›  Nick

XML序列化继承类时出现InvalidOperationException

  •  4
  • Nick  · 技术社区  · 16 年前

    我在将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 */ }
          }
       }
    }
    

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

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

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

    6 回复  |  直到 16 年前
        1
  •  2
  •   Jeff Sternal    16 年前

    如果可以将派生类重命名为与其基类不同的名称,则可以使用 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 或者其他一些过度杀戮的方法)。

        2
  •  5
  •   abatishchev Karl Johan    16 年前

    这对我们起了作用。

    [XmlType(TypeName = "DerivedClassA")] 
    
        3
  •  0
  •   marc_s MisterSmith    16 年前

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

    除了serializable属性之外,还需要使这两个属性中的一个具有不同的XML名称——正如错误所说,在“XML世界”中,它们都称为“ClassA”。其中一个必须使用 XmlElement

    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
  •  0
  •   Chris Martin    16 年前

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

    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
  •  0
  •   Jon    16 年前

    我也有同样的问题,但有一个附加的限制:不能访问域或派生类的源代码。从域对象继承的派生对象,并且由于类具有相同的非限定名称,XmlSerializer将无法序列化派生类的对象。

    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());
    

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

    推荐文章