gpt4 book ai didi

c# - 如何使用派生类进行XML序列化?

转载 作者:太空宇宙 更新时间:2023-11-03 12:24:15 24 4
gpt4 key购买 nike

我正在转换我的工作 XML 序列化,以便模型类继承抽象基类(以允许将来使用不同的序列格式)。

我的序列化工作正常,但当我切换到使用从基类派生的模型时,我遇到了各种异常,所以我不确定如何继续。

我的类基类是:

namespace Data
{
public abstract class Configuration
{
public abstract string Schema { get; set; }

public abstract Command[] Commands { get; set; }
}

public abstract class Command
{
public abstract string Name { get; set; }
}
}

我的派生具体类(在派生之前工作正常的类)然后在子命名空间中:

namespace Data.Xml
{
[Serializable()]
[XmlType(AnonymousType = true)]
[XmlRoot(Namespace = "", IsNullable = false)]
public class Configuration : Data.Configuration
{
[XmlAttribute("noNamespaceSchemaLocation",
Namespace = System.Xml.Schema.XmlSchema.InstanceNamespace)]
public override string Schema { get; set; }

[XmlArrayItem("Command", IsNullable = false)]
public override Data.Command[] Commands { get; set; }
}

[Serializable()]
public class Command : Data.Command
{
public override string Name { get; set; }
}
}

我在该子命名空间中调用序列化程序,如下所示:

public override Data.Configuration DeserializeConfig(StreamReader config)
{
var cs = new XmlSerializer(typeof(Configuration),
new Type[] { typeof(Command) });
return (Configuration)ConfigSerializer.Deserialize(ConfigStreamReader);
}

public override string SerializeConfig(Data.Configuration c, Encoding encoding)
{
string Output = null;
var Stream = new MemoryStream();
using (var Writer = new XmlTextWriter(Stream, encoding))
{
Writer.Formatting = Formatting.Indented;
XmlSerializerNamespaces ns = new XmlSerializerNamespaces();
ns.Add("xsi", XmlSchema.InstanceNamespace);
(new XmlSerializer(typeof(Configuration))).Serialize(Writer, c, ns);
Output = encoding.GetString(Stream.ToArray());
}
Stream.Dispose();
return Output;
}

生成的 XML 应该如下所示:

<?xml version="1.0" encoding="utf-8"?>
<Configuration
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:noNamespaceSchemaLocation="SomeSchema.xsd">
<Commands>
<Command>
<Name>SomeNameValue</Name>
</Command>
</Commands>
</Configuration>

我在尝试实例化序列化程序时看到以下异常(上面 DeserializeConfig() 方法中的第一行):

InvalidOperationException: Types 'Data.Command' and 'Data.Xml.Command' both use the XML type name, 'Command', from namespace ''. Use XML attributes to specify a unique XML name and/or namespace for the type.

我不太确定为什么序列化器试图从基类创建一些东西,确定名称是相同的,这是派生和命名空间等的想法...... 我如何正确标记这具有属性以使其正确反序列化?

仅供引用:我确实已经看到了几个关于此的问题,但答案似乎都足够具体,以至于我无法弄清楚如何将这些信息应用到这个看似简单的场景中.

更新:我想出了如何在实例化时将包含的类型传递给序列化程序,而不必注释基类,所以我从我的问题中删除了那部分并更新了代码。这已经过时了布鲁诺的建议和我的回应(尽管建议的问题仍然不适用)。

更新:我试图通过将派生类添加到命名空间(即添加 [XmlElement(Namespace = "http://www.foo.com/data/xml")] 到派生类中的每个属性)但这没有任何区别,因为序列化程序似乎仍然同时“看到”基类和派生类,因此认为它们都在该命名空间中.

最佳答案

最后翻转想通了大部分内容。

我退后一步,从一个非常简单的工作非派生示例开始,然后逐步达到我的需要。

这里发生了两件事。首先是冲突的类型名称,然后是冲突的属性名称。虽然我对其中的每一个都有一些了解,但组合在一起时用于构建每个选项的选项排列数量让我感到困惑。

为了防止抽象类型和派生类型名称在序列化时发生冲突,我需要使派生类类型匿名(此处使用 XmlType 属性)。

为了停止属性名称冲突,我需要忽略派生类中的属性基类。要在不编辑基类的情况下执行此操作,我遗漏了一个重要部分,XmlAttributeOverrides。我曾在 XmlSerializer.Serialize() 的 MSDN 文档中看到过这一点,但那里的信息很少解释它的相关内容。 This answer另一个问题让我想到了 David Woodward 的 excellent explanation .

我还没有尝试使用派生类型列表属性或反序列化进行任何此类尝试。

下面是一个程序的完整基本示例,它在控制台输出中输出带有一些序列化 XML 的字符串:

using System;
using System.Text;
using System.IO;
using System.Xml;
using System.Xml.Serialization;

namespace Test
{
class Program
{
static void Main(string[] args)
{
var TestBar = new MyXml.Bar()
{
Name = "John Smith",
};

Serializer s = new MyXml.Serializer();
var TestOutput = s.Serialize(TestBar);
Console.WriteLine(TestOutput);
}
}

public abstract class Bar
{
public abstract string Name { get; set; }
}

public abstract class Serializer
{
public abstract string Serialize(Bar bar);
}

namespace MyXml
{
public class Serializer : Test.Serializer
{
public override string Serialize(Test.Bar bar)
{
string Output = null;
var Stream = new MemoryStream();
var Encoding = new UTF8Encoding(false, true);

// Ignore the Name property in the *base* class!
var ao = new XmlAttributeOverrides();
var a = new XmlAttributes();
a.XmlElements.Clear(); // Clear any element attributes
a.XmlAttribute = null; // Remove any attribute attributes
a.XmlIgnore = true; // Set the ignore attribute value true
ao.Add(typeof(Test.Bar), "Name", a); // Set to use with Test.Bar.Name

using (var Writer = new XmlTextWriter(Stream, Encoding))
{
Writer.Formatting = Formatting.Indented;
var s = new XmlSerializer(typeof(Bar), ao);
s.Serialize(Writer, bar);
Output = Encoding.GetString(Stream.ToArray());
}
Stream.Dispose();
return Output;
}
}

[Serializable]
[XmlType(AnonymousType = true)] // Make type anonymous!
[XmlRoot(IsNullable = false)]
public class Bar : Test.Bar
{
[XmlIgnore] // Ignore the Name property in the *derived* class!
public override string Name
{
get => Unreverse(ReverseName);
set => ReverseName = Reverse(value);
}

[XmlElement("Name", IsNullable = false)]
public string ReverseName { get; set; }

private string Unreverse(string name)
{
return "John Smith"; // Smith, John -> John Smith
}

private string Reverse(string name)
{
return "Smith, John"; // John Smith -> Smith, John
}
}
}
}

关于c# - 如何使用派生类进行XML序列化?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/45884860/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com