[英]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.注意:不起作用我的意思是
InvalidOperationException
( BankPayment
不是预期的...... )被抛出。
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.