C# 使用 XmlInclude 或 SoapInclude 属性指定静态未知的类型
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/11886290/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Use the XmlInclude or SoapInclude attribute to specify types that are not known statically
提问by lsoliveira
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 InvalidOperationExceptionthat's caused by the serializer not knowing about the derived types of Payment.
AFAIK,有三种不同的方法可以解决InvalidOperationException由序列化程序不知道Payment.
1. Adding XmlIncludeto the Paymentclass definition:
1. 添加XmlInclude到Payment类定义:
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 XmlSerializerinstance
2. 在创建XmlSerializer实例期间传递派生类型的类型
Doesn't work.
不起作用。
3. Defining XmlAttributeOverridesfor 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 (XmlAttributeOverridesinitialization 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 XmlSerializerconstructor would then be used.
XmlSerializer然后将使用适当的构造函数。
NOTE: by doesn't workI mean the InvalidOperationException(BankPaymentwas not expected...) is thrown.
注意: by不起作用我的意思是InvalidOperationException(BankPayment不是预期的...) 被抛出。
Can anyone shed some light on the subject? How would one go about and debug the issue further?
任何人都可以对这个主题有所了解吗?如何进一步调试问题?
采纳答案by lsoliveira
Just solved the issue. After digging around for a while longer, I found this SO postwhich covers the exact same situation. It got me in the right track.
刚刚解决了这个问题。在挖掘了一段时间后,我发现了这篇 SO 帖子,其中涵盖了完全相同的情况。它让我走上了正轨。
Basically, the XmlSerializerneeds to know the default namespace ifderived classes are included as extra types. The exact reason why this has to happen is still unknown but, still, serialization is working now.
基本上,如果派生类作为额外类型包含在内,则XmlSerializer需要知道默认命名空间。必须发生这种情况的确切原因仍然未知,但是,序列化现在仍然有效。
回答by bizl
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)});
回答by derekantrican
Base on thisI was able to solve this by changing the constructor of XmlSerializerI 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();
}
回答by A. Dady
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,并且仍然能够在对象序列化之前执行您需要的操作。
回答by Hamit YILDIRIM
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;
}
}

