gpt4 book ai didi

c# - 多态类型和 IXmlSerializable

转载 作者:太空狗 更新时间:2023-10-29 17:57:48 24 4
gpt4 key购买 nike

.NET 中的 XML 序列化通过 XmlSerializer 构造函数的 extraTypes[] 参数允许多态对象。它还允许为实现 IXmlSerializable 的类型自定义 XML 序列化。

但是,我无法将这两个功能结合起来——如这个最小示例所示:

using System;
using System.IO;
using System.Xml;
using System.Xml.Schema;
using System.Xml.Serialization;

namespace CsFoo
{
public class CustomSerializable : IXmlSerializable
{
public XmlSchema GetSchema() { return null; }
public void ReadXml(XmlReader xr) { }
public void WriteXml(XmlWriter xw) { }
}

class CsFoo
{
static void Main()
{
XmlSerializer xs = new XmlSerializer(
typeof(object),
new Type[] { typeof(CustomSerializable) });

xs.Serialize(new StringWriter(), new CustomSerializable());
}
}

最后一行抛出 System.InvalidOperationException 并显示以下消息:

The type CsFoo.CustomSerializable may not be used in this context to use CsFoo.CustomSerializable as a parameter, return type, or member of a class or struct, the parameter, return type, or member must be declared as type CsFoo.CustomSerializable (it cannot be object). Objects of type CsFoo.CustomSerializable may not be used in un-typed collections, such as ArrayLists.

通过动态生成的 XML 程序集,我们最终通过调用返回到 .NET 标准库代码:

System.Xml.Serialization.XmlSerializationWriter.WriteTypedPrimitive(
String, String, Object, Boolean) : Void

反过来,这会导致:

protected Exception CreateUnknownTypeException(Type type)
{
if (typeof(IXmlSerializable).IsAssignableFrom(type))
{
return new InvalidOperationException(
Res.GetString("XmlInvalidSerializable",
new object[] { type.FullName }));
}

// Rest omitted...

Reflector 显示 XmlInvalidSerializable 资源对应于上面的字符串——即,WriteTypedPrimitive 不喜欢 IXmlSerializable

如果我们生成一个非多态的序列化器,像这样:

XmlSerializer xs = new XmlSerializer(typeof(CustomSerializable));

.NET 将生成对以下内容的调用:

System.Xml.Serialization.XmlSerializationWriter.WriteSerializable(
IXmlSerializable, String, String, Boolean) : Void

这会正确处理 IXmlSerializable。有人知道为什么 .NET 在多态情况下不使用这个函数吗?查看 XML 序列化程序生成的 C#,在我看来这可以很容易地完成。这是我从 XML 序列化程序中获得的一些代码,其中包含一个未经测试的解决方案:

void Write1_Object(string n, string ns, global::System.Object o, 
bool isNullable, bool needType)
{
if ((object)o == null)
{
if (isNullable) WriteNullTagLiteral(n, ns);
return;
}
if (!needType)
{
System.Type t = o.GetType();
if (t == typeof(global::System.Object))
{
}
>>> patch begin <<<
+ else if (typeof(IXmlSerializable).IsAssignableFrom(t))
+ {
+ WriteSerializable((System.Xml.Serialization.IXmlSerializable)
((global::CsFoo.CustomSerializable)o),
+ @"CustomSerializable", @"", true, true);
+ }
>>> patch end <<<
else
{
WriteTypedPrimitive(n, ns, o, true);
return;
}
}
WriteStartElement(n, ns, o, false, null);
WriteEndElement(o);
}

这是否出于技术原因或仅仅是功能限制而被遗漏?不支持的功能,还是我的白痴?我的 intertubes Google 技能让我失望了。

我确实在这里找到了一些相关问题,其中“C# Xml-Serializing a derived class using IXmlSerializable”最相关。这让我相信这是不可能的。

在那种情况下,我目前的想法是在根基类中注入(inject)默认的 IXmlSerializable 实现。然后一切都将是一个 IXmlSerializable,并且 .NET 不会提示。我可以使用 Reflection.Emit 为每个具体类型生成 ReadXmlWriteXml 主体,生成的 XML 看起来与我使用库一时一样。

有些人在遇到 XML 序列化问题时会想“我知道,我会使用 Reflection.Emit 来生成代码”。现在他们有两个问题。


附言笔记;我知道 .NET 的 XML 序列化的替代方案,并且知道它有局限性。我还知道保存 POCO 比处理抽象数据类型要简单得多。但是我有一堆遗留代码,需要对现有 XML 模式的支持。

因此,虽然我很欣赏显示这在 SomeOtherXMLYAMLXAMLProtocolBuffers 中有多么容易的回复、DataContractRandomJsonLibraryThrift 或您的 MorseCodeBasedSerializeToMp3 库 - 嘿,我可能会学到一些东西 -,我什么我希望有一个 XML 序列化程序解决方案,如果不是解决方案的话。

最佳答案

当使用 object 时,我能够重现您的问题:

XmlSerializer xs = new XmlSerializer(
typeof(object),
new Type[] { typeof(CustomSerializable) });

但是,我随后创建了 CustomSerializable 的派生类:

public class CustomSerializableDerived : CustomSerializable
{
}

并尝试序列化它:

XmlSerializer xs = new XmlSerializer(
typeof(CustomSerializable),
new Type[] { typeof(CustomSerializableDerived) });

这有效。

因此,问题似乎仅限于您将“对象”指定为要序列化的类型的情况,但如果您指定具体的基类型则不会。

我会在早上对此进行更多研究。

关于c# - 多态类型和 IXmlSerializable,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/631852/

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