【问题标题】:Use the XmlInclude or SoapInclude attribute to specify types that are not known statically使用 XmlInclude 或 SoapInclude 属性指定静态未知的类型
【发布时间】:2012-08-06 20:21:27
【问题描述】:

在使用 .NET 的XmlSerializer 时,我遇到了一个非常奇怪的问题。

采取以下示例类:

public class Order 
{
    public PaymentCollection Payments { get; set; }

    //everything else is serializable (including other collections of non-abstract types)
}

public class PaymentCollection : Collection<Payment>
{
}

public abstract class Payment 
{
    //abstract methods
}

public class BankPayment : Payment
{
    //method implementations
}

AFAIK,有三种不同的方法可以解决由于序列化程序不知道Payment 的派生类型而导致的InvalidOperationException

1.将XmlInclude 添加到Payment 类定义中:

这是不可能的,因为所有类都作为我无法控制的外部引用包含在内。

2。在创建XmlSerializer 实例期间传递派生类型的类型

没用。

3。为目标属性定义XmlAttributeOverrides 以覆盖属性的默认序列化(如this SO post 中所述)

也不起作用(XmlAttributeOverrides 初始化如下)。

Type bankPayment = typeof(BankPayment);

XmlAttributes attributes = new XmlAttributes();
attributes.XmlElements.Add(new XmlElementAttribute(bankPayment.Name, bankPayment));

XmlAttributeOverrides overrides = new XmlAttributeOverrides();
overrides.Add(typeof(Order), "Payments", attributes);

然后将使用适当的XmlSerializer 构造函数。

注意:不起作用我的意思是 InvalidOperationExceptionBankPayment 不是预期的......)被抛出。

任何人都可以对这个主题有所了解吗?如何进一步解决问题?

【问题讨论】:

    标签: c# .net xml xmlserializer


    【解决方案1】:

    这对我有用:

    [XmlInclude(typeof(BankPayment))]
    [Serializable]
    public abstract class Payment { }    
    
    [Serializable]
    public class BankPayment : Payment {} 
    
    [Serializable]
    public class Payments : List<Payment>{}
    
    XmlSerializer serializer = new XmlSerializer(typeof(Payments), new Type[]{typeof(Payment)});
    

    【讨论】:

    • 所以基类型需要知道它的所有实现?这似乎不是一个很好的解决方案。没有别的办法吗?
    • @AlexanderStolz 用于在创建 XmlSerializable 对象时传递新类型的通用实现是最佳解决方案。如前所述stackoverflow.com/a/2689660/698127
    • [Serializable] 属性不是必需的。您只需要通过抽象类的名称指定期望序列化的类型 - 使用 XmlInclude 属性。
    【解决方案2】:

    刚刚解决了这个问题。在挖掘了一段时间后,我发现this SO post 涵盖了完全相同的情况。它让我走上了正轨。

    基本上,XmlSerializer 需要知道默认命名空间 if 派生类作为额外类型包含在内。必须发生这种情况的确切原因仍然未知,但序列化现在仍在工作。

    【讨论】:

      【解决方案3】:

      基于this,我能够通过更改我正在使用的XmlSerializer 的构造函数而不是更改类来解决这个问题。

      而不是使用这样的东西(建议在其他答案中):

      [XmlInclude(typeof(Derived))]
      public class Base {}
      
      public class Derived : Base {}
      
      public void Serialize()
      {
          TextWriter writer = new StreamWriter(SchedulePath);
          XmlSerializer xmlSerializer = new XmlSerializer(typeof(List<Derived>));
          xmlSerializer.Serialize(writer, data);
          writer.Close();
      }
      

      我这样做了:

      public class Base {}
      
      public class Derived : Base {}
      
      public void Serialize()
      {
          TextWriter writer = new StreamWriter(SchedulePath);
          XmlSerializer xmlSerializer = new XmlSerializer(typeof(List<Derived>), new[] { typeof(Derived) });
          xmlSerializer.Serialize(writer, data);
          writer.Close();
      }
      

      【讨论】:

        【解决方案4】:

        只需在 Base 中进行,这样任何子级都可以序列化,代码更简洁。

        public abstract class XmlBaseClass  
        {
          public virtual string Serialize()
          {
            this.SerializeValidation();
        
            XmlSerializerNamespaces XmlNamespaces = new XmlSerializerNamespaces(new[] { XmlQualifiedName.Empty });
            XmlWriterSettings XmlSettings = new XmlWriterSettings
            {
              Indent = true,
              OmitXmlDeclaration = true
            };
        
            StringWriter StringWriter = new StringWriter();
        
            XmlSerializer Serializer = new XmlSerializer(this.GetType());
            XmlWriter XmlWriter = XmlWriter.Create(StringWriter, XmlSettings);
            Serializer.Serialize(XmlWriter, this, XmlNamespaces);
            StringWriter.Flush();
            StringWriter.Close();
        
            return StringWriter.ToString();
        
          }
        
          protected virtual void SerializeValidation() {}
        }
        
        [XmlRoot(ElementName = "MyRoot", Namespace = "MyNamespace")]
        public class XmlChildClass : XmlBaseClass
        {
          protected override void SerializeValidation()
          {
            //Add custom validation logic here or anything else you need to do
          }
        }
        

        这样,您可以在任何情况下对子类调用 Serialize,并且仍然能够在对象序列化之前执行您需要做的事情。

        【讨论】:

        • 我想突出显示代码行,这对于可视化我们可以避免 XmlInclude 或其他属性的方式很重要:XmlSerializer Serializer = new XmlSerializer(this.GetType());
        【解决方案5】:

        我同意 bizl

        [XmlInclude(typeof(ParentOfTheItem))]
        [Serializable]
        public abstract class WarningsType{ }
        

        如果您需要将此包含的类应用于对象项,您可以这样做

        [System.Xml.Serialization.XmlElementAttribute("Warnings", typeof(WarningsType))]
        public object[] Items
        {
            get
            {
                return this.itemsField;
            }
            set
            {
                this.itemsField = value;
            }
        }
        

        【讨论】:

          猜你喜欢
          • 2020-07-20
          • 1970-01-01
          • 1970-01-01
          • 2013-11-28
          • 1970-01-01
          • 1970-01-01
          • 2021-08-26
          • 2020-10-09
          相关资源
          最近更新 更多