在.NET XML反序列化中,如何允许多态使用Array类型?

示例架构:

... ...            

通过.NET运行此wsdl.exe会生成类似于以下内容的代码:

 [System.Xml.Serialization.XmlIncludeAttribute(typeof(Dog[]))] public partial class Dog { ... } public partial class Cat { ... } public partial class Foo { private string barField; private object bazField; } 

似乎wsdl.exe试图“智能”并意识到我的ArrayOfDog实际上只是一个可以编码为C#数组的包装类型。 当在另一种数据类型中显式引用ArrayOfDog时,这可以正常工作。 但是,当多态地使用ArrayOfDog时(例如,作为xsd:anyType的替换),这会中断。 它似乎打破了,因为.NET运行时对名为“ArrayOfDog”的complexType一无所知 – 它基本上抛弃了这些信息,转而使用原生C#数组。

示例XML文档1:

  Hello  ...   

示例XML文档2:

  Hello  ... ...   

文档#1由运行时正确反序列化。 我得到了一个类型为Foo的对象,其中包含Bar和Baz的正确反序列化字段。

文档#2被运行时错误地反序列化。 我得到一个类型为Foo的对象,其中有一个正确的反序列化字段用于Bar,但对于Baz字段,我得到System.XML.XMLNode []。 我的猜测是因为运行时对名为“ArrayOfDog”的实体的任何类型绑定都一无所知。 您可能认为XmlInclude指令“XmlIncludeAttribute(typeof(Dog []))”将处理此问题,但它似乎不起作用。

有人遇到过这个吗?

这里有优雅的解决方案吗? 我正在考虑使用的解决方法是将我的“ArrayOf”类型包装在另一种类型中,并将其包含在xsd:anyType的替换中。

我不认为这与多态性有任何关系。 我认为这是XML Serializer中的一个错误,假设任何名为“ArrayOfDog”的类型,包含一个“Dog”序列,意味着代表Dog []。 作为对该理论的测试,尝试更改WSDL以使用名称“BunchOfDogs”,并查看是否更改了客户端中的代理代码。

如果你想在XML中使用多态,那么ArrayOfDog和Cat都需要是相同基类型的扩展(除了xsd:any)。 如果是这种情况,那么我希望.NET能够生成Baz作为基类型。

使用xsd的模式:任何原因都会导致问题。 那里几乎可以有任何东西,有些组合根本没有意义。

您还没有说过这个Java服务是来自Axis,还是它的版本。 我已经看到Axis表现得好像xsi:type是有效模式的替代品。 小心需要“正确”使用xsi:type的模式。

你想从什么开始? 如果您从这样定义的类型开始:

 public partial class Foo { private string _bar; private object[] _baz; public string Bar { get { return _bar; } set { _bar= value; } } [XmlArray("Baz")] [XmlArrayItem("Type1", typeof(Type1))] public object[] Baz { get { return _baz; } set { _baz= value; } } } 

然后,您可以像文档#2一样序列化和反序列化文档。

好像你想要从WSDL和XSD开始。 在这种情况下,您可以概括您的架构看起来像这样:

                     

以上架构生成此代码:

 public partial class Foo { private string barField; private object[] bazField; ///  public string Bar { get { return this.barField; } set { this.barField = value; } } ///  [System.Xml.Serialization.XmlArrayItemAttribute("", typeof(System.Xml.XmlElement), IsNullable=false)] [System.Xml.Serialization.XmlArrayItemAttribute(typeof(Type1), IsNullable=false)] public object[] Baz { get { return this.bazField; } set { this.bazField = value; } } } 

如果要包含其他类型,请根据需要将元素添加到xsd:choice中。

由于你想在其中允许xsd:any,因此Foo.Baz是一个对象数组。 它上面的编程模型要求你用(foo.Baz [i]作为Type1)测试或转换每个元素。