【问题标题】:How to use a custom IXmlSerializable as an XmlAttribute?如何使用自定义 IXmlSerializable 作为 XmlAttribute?
【发布时间】:2012-07-23 01:11:16
【问题描述】:

我为下面的类型实现了IXmlSerializable,它将 RGB 颜色值编码为单个字符串:

public class SerializableColor : IXmlSerializable
{
    public int R { get; set; }
    public int G { get; set; }
    public int B { get; set; }

    public XmlSchema GetSchema()
    {
        return null;
    }

    public void ReadXml(XmlReader reader)
    {
        var data = reader.ReadString();
        reader.ReadEndElement();
        var split = data.Split(' ');
        R = int.Parse(split[0]);
        G = int.Parse(split[1]);
        B = int.Parse(split[2]);
    }

    public void WriteXml(XmlWriter writer)
    {
        writer.WriteString(R + " " + G + " " + B);
    }
}

由于它是单个字符串,我想将其存储为属性以节省空间。但是,一旦我将 [XmlAttribute] 添加到我的属性中,就会出现以下异常:

{"无法序列化 SerializableColor 类型的成员 'Color'。XmlAttribute/XmlText 不能用于编码实现 IXmlSerializable 的类型。"}

有没有办法让它也作为一个属性工作?

【问题讨论】:

    标签: c# xml


    【解决方案1】:

    可悲(奇怪)根据此链接http://connect.microsoft.com/VisualStudio/feedback/details/277641/xmlattribute-xmltext-cannot-be-used-to-encode-types-implementing-ixmlserializable是不可能的

    为了解决这个问题,我目前正在使用 XmlIgnore 属性来隐藏复杂属性并通过另一个属性将其公开为字符串

    public class MyDto
    {
        [XmlAttribute(AttributeName = "complex-attribute")]
        public string MyComplexPropertyAsString
        {
            get { return MyComplexMember.ToString(); }
            set { MyComplexMember.LoadFromString(value); }
        }
        [XmlIgnore]
        public MyComplexMember At { get; set; }
    }
    

    【讨论】:

    • 这种解决方法有一个不希望的副作用,即MyComplexMember 关联的任何 XML 模式类型都会丢失。这对序列化的 XML 没有影响,但任何生成的模式或 WSDL 现在都是错误的。
    【解决方案2】:

    错误的意思正是它所说的。在实现 IXmlSerializable 时,您不能使用这些 XML 序列化属性,因为 IXmlSerializable 期望 XML 序列化是完全自定义的。如果您想使用 XmlSerializer 使用属性使类可序列化,则可以这样做。

    [XmlRoot("SerializableColor")]
    public class SerializableColor
    {
        [XmlAttribute("R")]
        public int R { get; set; }
        [XmlAttribute("G")]
        public int R { get; set; }
        [XmlAttribute("B")]
        public int B { get; set; }    
    }
    

    另外,对于 XmlSerializable 的实现:

        public void ReadXml(XmlReader reader)
        {
            string data = null;
    
            reader.MoveToAttribute("Color");
            if (reader.ReadAttributeValue())
            {
                data = reader.Value;
            }
            reader.ReadEndElement();
    
            var split = data.Split(' ');
            R = int.Parse(split[0]);
            G = int.Parse(split[1]);
            B = int.Parse(split[2]);
        }
    
        public void WriteXml(XmlWriter writer)
        {
            writer.WriteAttributeString("Color", R + " " + G + " " + B);
        }
    

    另一方面,如果您希望能够做的只是有一个可逆颜色的短字符串表示,请查看ColorTranslator Class。特别是,请参阅 FromHtml 和 ToHtml 方法。

    【讨论】:

    • 感谢您的回答。我有两个问题。首先,如何实现不正确?看起来很像in the documentation 给出的示例(在评论部分描述了附录)。其次,示例中的 XmlRoot 属性是否相关?它有什么不同?
    • 关于实现不产生正确的 XML,我忘记了“框架编写了一个包装器元素并在 XML 编写器启动后定位它。”我会修改答案。实际上,您可以将 XmlRoot 排除在外,因为它可以由 XmlSerializer 推断出来,但是,当我覆盖类的默认序列化行为时,为了清楚起见,我通常会在它的所有组件上执行此操作。
    • 我投了反对票,因为 OP 正在询问谁来创建可自定义的 XML 属性。不生成 XML 元素。
    • 有趣的@RichardSchneider 作为提出问题的人发现这是可以接受的答案,并且其中的两组代码实际上都在 XML 中产生了一个属性,您的反对票没有任何意义。也许你应该再读一遍,也许尝试执行代码。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-06-12
    • 2017-03-08
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多