简体   繁体   English

使用 XmlInclude 或 SoapInclude 属性指定静态未知的类型

[英]Use the XmlInclude or SoapInclude attribute to specify types that are not known statically

I've got a very strange problem when working with .NET's XmlSerializer .使用 .NET 的XmlSerializer时,我遇到了一个非常奇怪的问题。

Take the following example classes:采取以下示例类:

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, there are three different methods to solve the InvalidOperationException that's caused by the serializer not knowing about the derived types of Payment . AFAIK,有三种不同的方法可以解决因序列化程序不知道Payment的派生类型而导致的InvalidOperationException

1. Adding XmlInclude to the Payment class definition: 1.在Payment class定义中添加XmlInclude

This is not possible due to all classes being included as external references over which I have no control of.这是不可能的,因为所有类都包含在我无法控制的外部引用中。

2. Passing the derived types' types during creation of the XmlSerializer instance 2. 在创建XmlSerializer实例期间传递派生类型的类型

Doesn't work.不工作。

3. Defining XmlAttributeOverrides for the target property in order to override the property's default serialization (as explained in this SO post ) 3. 为目标属性定义XmlAttributeOverrides以覆盖属性的默认序列化(如本 SO 帖子中所述)

Also doesn't work ( XmlAttributeOverrides initialization follows).也不起作用( 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);

The appropriate XmlSerializer constructor would then be used.然后将使用适当的XmlSerializer构造函数。

NOTE: by doesn't work I mean the InvalidOperationException ( BankPayment was not expected... ) is thrown.注意:不起作用我的意思是InvalidOperationExceptionBankPayment不是预期的...... )被抛出。

Can anyone shed some light on the subject?任何人都可以对这个主题有所了解吗? How would one go about and debug the issue further?一个 go 将如何进一步调试问题?

This worked for me:这对我有用:

[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)});

Just solved the issue.刚刚解决了这个问题。 After digging around for a while longer, I found this SO post which covers the exact same situation.在挖掘了一段时间后,我发现了这篇 SO 帖子,其中涵盖了完全相同的情况。 It got me in the right track.它让我走上了正轨。

Basically, the XmlSerializer needs to know the default namespace if derived classes are included as extra types.基本上,如果派生类作为额外类型包含在内,则XmlSerializer需要知道默认命名空间。 The exact reason why this has to happen is still unknown but, still, serialization is working now.必须发生这种情况的确切原因仍然未知,但是,序列化现在仍然有效。

Base on this I was able to solve this by changing the constructor of XmlSerializer I was using instead of changing the classes.基于此,我能够通过更改我使用的XmlSerializer的构造函数而不是更改类来解决此问题。

Instead of using something like this (suggested in the other answers):而不是使用这样的东西(在其他答案中建议):

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

I did this:我这样做了:

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

Just do it in the Base, that way any child can be Serialized, less code cleaner code.只需在 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
  }
}

This way you can call Serialize on the child class no matter the circumstance and still be able to do what you need to before object Serializes.通过这种方式,无论情况如何,您都可以在子类上调用 Serialize,并且仍然能够在对象序列化之前执行您需要的操作。

I agree with bizl我同意 bizl

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

also if you need to apply this included class to an object item you can do like that此外,如果您需要将此包含的类应用于对象项,您可以这样做

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

I added this [System.Xml.Serialization.XmlAttributeAttribute()] for property, its resolved for me.我为属性添加了这个[System.Xml.Serialization.XmlAttributeAttribute()] ,它为我解决了。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

相关问题 “不希望使用RoleProxy类型。 使用XmlInclude或SoapInclude属性可以指定静态未知的类型。” NHibernate - “The type RoleProxy was not expected. Use the XmlInclude or SoapInclude attribute to specify types that are not known statically.” NHibernate xxx类型不是预期的。 使用XmlInclude或SoapInclude属性来指定静态未知的类型 - The type xxx was not expected. Use the XmlInclude or SoapInclude attribute to specify types that are not known statically ASMX 服务错误 - 使用 XmlInclude 或 SoapInclude 属性指定静态未知的类型 - ASMX Service Error - Use the XmlInclude or SoapInclude attribute to specify types that are not known statically 调用Web服务时出现问题-使用XmlInclude或SoapInclude属性 - Issue calling a web service - Use the XmlInclude or SoapInclude attribute 如何使用XmlInclude动态指定类型? - How to use XmlInclude to specify types dynamically? 类型xxxx不期望使用xmlinclude或soapinclude - type xxxx not expected use xmlinclude or soapinclude Xml序列化异常:不需要类型UserQuery + SpecificContentItem。 使用XmlInclude或SoapInclude - Xml serialization Exception : The type UserQuery+SpecificContentItem was not expected. Use the XmlInclude or SoapInclude XmlInclude属性和派生类 - XmlInclude attribute and derived classes 如何动态添加XmlInclude属性 - How to add XmlInclude attribute dynamically WCF - 指定已知类型(PCL / .NET标准) - WCF - Specify Known Types (PCL / .NET Standard)
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM