Warning: file_get_contents(/data/phpspider/zhask/data//catemap/1/visual-studio-2008/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# 如何使用XmlSerializer序列化派生实例?_C#_Xmlserializer_Derived Class - Fatal编程技术网

C# 如何使用XmlSerializer序列化派生实例?

C# 如何使用XmlSerializer序列化派生实例?,c#,xmlserializer,derived-class,C#,Xmlserializer,Derived Class,我意识到这看起来是一个完全相同的问题,但我不知道如何按照同一个问题的指导来实现这一点: using System; using System.Text; using System.Xml; using System.Xml.Schema; using System.Xml.Serialization; namespace xmlSerializerLab { public class Utf8StringWriter : System.IO.StringWriter {

我意识到这看起来是一个完全相同的问题,但我不知道如何按照同一个问题的指导来实现这一点:

using System;
using System.Text;
using System.Xml;
using System.Xml.Schema;
using System.Xml.Serialization;

namespace xmlSerializerLab
{
    public class Utf8StringWriter : System.IO.StringWriter
    {
        public override Encoding Encoding => Encoding.UTF8;
    }

    [XmlRoot(ElementName = "Query", Namespace = "http://www.opengis.net/wfs")]
    public class Query
    {
        [XmlElement(ElementName = "Filter", Namespace = "http://www.opengis.net/ogc")]
        public Filter Filter { get; set; }
    }

    [XmlInclude(typeof(PropertyIsOpFilter))]
    [XmlInclude(typeof(PropertyIsEqualToFilter))]
    [XmlInclude(typeof(OpFilterBase))]
    [XmlInclude(typeof(LiteralFilter))]
    [XmlInclude(typeof(Query))]
    [Serializable]
    public class Filter
    {
        [XmlElement]
        public Filter And { get; set; }
    }

    public class PropertyIsOpFilter : Filter, IXmlSerializable
    {

        public Filter LeftOp { get; set; }

        public Filter RightOp { get; set; }

        public XmlSchema GetSchema()
        {
            return null;
        }

        public void ReadXml(XmlReader reader) { }

        public void WriteXml(XmlWriter writer)
        {
            Program.ToXml(LeftOp, writer);
            Program.ToXml(RightOp, writer);
        }
    }

    [XmlRoot("IsEqualTo")]
    public class PropertyIsEqualToFilter : PropertyIsOpFilter { }

    public class OpFilterBase : Filter, IXmlSerializable
    {
        public string Op { get; set; }
        public object Value { get; set; }

        public XmlSchema GetSchema()
        {
            return null;
        }

        public void ReadXml(XmlReader reader) { }

        public void WriteXml(XmlWriter writer)
        {
            if (!String.IsNullOrEmpty(Op))
            {
                writer.WriteStartElement(Op);
                writer.WriteValue(Value);
                writer.WriteEndElement();
            }
            else
            {
                writer.WriteValue(Value);
            }
        }
    }

    public class LiteralFilter : OpFilterBase { }


    class Program
    {
        public static void ToXml(Object o, XmlWriter writer)
        {
            var inputSerializer = new XmlSerializer(o.GetType(), new Type[] {
                typeof(Filter),
                typeof(PropertyIsOpFilter),
                typeof(PropertyIsEqualToFilter),
                typeof(OpFilterBase),
                typeof(LiteralFilter),
                typeof(Query)
            });
            inputSerializer.Serialize(writer, o);
        }

        public static string ToXml(Object o)
        {
            var inputSerializer = new XmlSerializer(o.GetType());
            using (var writer = new Utf8StringWriter())
            {
                using (var xmlWriter = new XmlTextWriter(writer))
                {
                    ToXml(o, xmlWriter);
                }
                return writer.ToString();
            }
        }

        static void Main(string[] args)
        {
            Filter o = new PropertyIsEqualToFilter()
            {
                LeftOp = new LiteralFilter()
                {
                    Value = 1
                },
                RightOp = new LiteralFilter()
                {
                    Value = 1
                }
            };

            var query = new Query()
            {
                Filter = o
            };

            Console.WriteLine(ToXml(query));
            Console.ReadLine();
        }
    }
}
它会导致以下异常:

InvalidOperationException:类型 xmlSerializerLab.PropertyIsEqualToFilter不能在此过程中使用 上下文将xmlSerializerLab.PropertyIsEqualToFilter用作 参数、返回类型或类或结构的成员, 返回类型,或必须将成员声明为类型 xmlSerializerLab.PropertyIsEqualToFilter(不能是对象)。 xmlSerializerLab.PropertyIsEqualToFilter类型的对象可能不可用 用于非类型集合,如ArrayList

据我所知,我需要在PropertyOpfilter和OpFilterBase上使用IXmlSerializable,因为我正试图以所描述的特定XML格式为目标。但是我发现我还必须使查询类IXmlSerializable

下面是一个示例XML文档,我希望能够从模型中生成该文档:

<GetFeature xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema"
  service="WFS"
  version="1.1.0"
  maxFeatures="0" xmlns="http://www.opengis.net/wfs">
  <ResultType>Results</ResultType>
  <OutputFormat>text/gml; subtype=gml/3.1.1</OutputFormat>
  <Query
    d2p1:srsName="EPSG:4326" xmlns:d2p1="http://www.opengis.net/ogc">
    <d2p1:Filter>
      <d2p1:IsEqualTo>
        <d2p1:PropertyName>Prop1</d2p1:PropertyName>
        <d2p1:Literal>1</d2p1:Literal>
      </d2p1:IsEqualTo>
    </d2p1:Filter>
  </Query>
</GetFeature>

结果
text/gml;子类型=gml/3.1.1
建议1
1.

通过使查询类IXmlSerializable并编写一些好的WriteXml和ReadXml逻辑,我可以让它工作,但我希望它能够工作,而不必做所有这些,因为XmlRoot、XmlAttribute和XmlElement标记应该为序列化程序提供足够的信息,让它知道根据标记名实例化哪个类(匹配ElementName)以及如何基于属性进行序列化。

您看到的问题可以通过以下最小示例重现:

public class BaseClass
{
}

public class DerivedClass : BaseClass, IXmlSerializable
{
    #region IXmlSerializable Members

    public XmlSchema GetSchema() { return null; }

    public void ReadXml(XmlReader reader) { throw new NotImplementedException(); }

    public void WriteXml(XmlWriter writer) { }

    #endregion
}
使用序列化代码:

BaseClass baseClass = new DerivedClass();

using (var textWriter = new StringWriter())
{
    using (var xmlWriter = XmlWriter.Create(textWriter))
    {
        var serializer = new XmlSerializer(typeof(BaseClass), new Type[] { typeof(DerivedClass) });
        serializer.Serialize(xmlWriter, baseClass);
    }
    Console.WriteLine(textWriter.ToString());
}
将引发以下异常(示例):

这是我在
XmlSerializer
中看到的最没有帮助的异常消息之一。要了解异常,您需要了解
XmlSerializer
如何通过处理多态性。如果我从
DerivedClass
中删除
IXmlSerializable
,将生成以下XML():

注:

  • 要使
    [xmlclude]
    机制工作,所有包含的类型显然必须与基类型位于同一个XML命名空间中。为了确保这一点,我将
    [XmlRoot(namespace=XmlNamespaces.OpengisWfs)]
    添加到所有
    过滤器
    子类型中

  • [xmlclude(typeof(DerivedType))]
    属性可以添加到其直接父类型或最低公共基类型。在上面的代码中,我将属性添加到直接父类型,以便成功序列化中间类型的成员,例如:

    public class SomeClass
    {
        PropertyIsOpFilter  IsOpFilter { get; set; }
    }
    
  • >P>考虑不能实例化的中间类型为<代码>抽象> <代码>,例如“代码>公共抽象类过滤器< /代码>。考虑标记为“最派生”的类型为<代码>密封< /代码>,例如“代码>公共密封类文字过滤器

  • 如果使用
    新的XmlSerializer(Type,Type[])
    构造函数,则必须静态缓存序列化程序,以避免严重的内存泄漏,如前所述。这在我的解决方案中不是必需的,但在您的问题中使用它

显示以下XML已成功生成的示例:

<Query xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://www.opengis.net/wfs">
  <Filter xsi:type="PropertyIsEqualToFilter">
    <LeftOp xsi:type="LiteralFilter">
      <Value xsi:type="xsd:int">1</Value>
    </LeftOp>
    <RightOp xsi:type="LiteralFilter">
      <Value xsi:type="xsd:int">1</Value>
    </RightOp>
  </Filter>
</Query>

1.
1.

回答得很好!我的两位同事提供了相同的解决方案,但没有说得这么清楚!但我无权更改XML格式。我正在尝试生成与OGC WFS兼容的XML。这里可以找到一个更复杂的示例:。我将更新问题,以包含此重要约束。根据您的分析是的,XmlInclude似乎不在讨论范围内。@CoreyAlix-也许你需要问第二个问题。你回答了我的明确问题(是的,可以做到)和我的隐含问题(不,我无法通过编写IXmlSerializable类获得我要找的XML)@CoreyAlix-实际上,您可能可以使用而不是
xmlclude
。但是我们需要查看所需的XML,而不是所需的类,这就是为什么我建议您问另一个问题。
public static class XmlNamespaces
{
    public const string OpengisWfs = "http://www.opengis.net/wfs";
}

[XmlRoot(Namespace = XmlNamespaces.OpengisWfs)]
public class Query
{
    public Filter Filter { get; set; }
}

[XmlInclude(typeof(PropertyIsOpFilter))]
[XmlInclude(typeof(OpFilterBase))]
[XmlRoot(Namespace = XmlNamespaces.OpengisWfs)]
public class Filter
{
    [XmlElement]
    public Filter And { get; set; }
}

[XmlInclude(typeof(PropertyIsEqualToFilter))]
[XmlRoot(Namespace = XmlNamespaces.OpengisWfs)]
public class PropertyIsOpFilter : Filter
{
    public Filter LeftOp { get; set; }

    public Filter RightOp { get; set; }
}

[XmlRoot("IsEqualTo", Namespace = XmlNamespaces.OpengisWfs)]
public class PropertyIsEqualToFilter : PropertyIsOpFilter { }

[XmlInclude(typeof(LiteralFilter))]
[XmlRoot(Namespace = XmlNamespaces.OpengisWfs)]
public class OpFilterBase : Filter
{
    public string Op { get; set; }
    public object Value { get; set; }
}

[XmlRoot(Namespace = XmlNamespaces.OpengisWfs)]
public class LiteralFilter : OpFilterBase { }
public class SomeClass
{
    PropertyIsOpFilter  IsOpFilter { get; set; }
}
<Query xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://www.opengis.net/wfs">
  <Filter xsi:type="PropertyIsEqualToFilter">
    <LeftOp xsi:type="LiteralFilter">
      <Value xsi:type="xsd:int">1</Value>
    </LeftOp>
    <RightOp xsi:type="LiteralFilter">
      <Value xsi:type="xsd:int">1</Value>
    </RightOp>
  </Filter>
</Query>