【问题标题】:C# Serializing XmlElement with XmlTextC# 使用 XmlText 序列化 XmlElement
【发布时间】:2017-12-04 20:39:22
【问题描述】:

我需要复制这种 XML 格式:

<item>
    <attribute1>1</attribute1>
    <attribute2 something="true">
        2
    </attribute2>
    <attribute3 something="false">
        3
    </attribute3>
    <!-- goes on until attribute25 -->
</item>

我目前正在使用这样的东西来实现我想要的:

Item.cs:

[XmlType(TypeName = "item")]
public class Item {

    [XmlElement("attribute1")]
    public CustomElement<string> Attribute1 { get; set; }

    [XmlElement("attribute2")]
    public CustomElement<string> Attribute2 { get; set; }

    [XmlElement("attribute3")]
    public CustomElement<string> Attribute3 { get; set; }

    // Etc Etc
}

CustomElement.cs:

/// <summary>
///     Represents a CustomElement.
/// </summary>
/// <typeparam name="T">The type for the value of the element.</typeparam>

public class CustomElement<T>
{
    [XmlIgnore] public T Value;

    [XmlText]
    public T XmlValue => Value;

    public CustomElement()
    {
    }

    public CustomElement(T value)
    {
        Value = value;
    }

    [XmlIgnore]
    public bool? Something { get; set; }

    [XmlAttribute("something")]
    public bool XmlSomething
    {
        get => Something != null && Something.Value;
        set => Something = value;
    }

    public bool XmlSomethingSpecified => Something.HasValue;

    public static implicit operator CustomElement<T>(T x)
    {
        return new CustomElement<T>(x);
    }
}

但是,在序列化我的Item 之后,我得到:

<item>
    <attribute1 />
    <attribute2 />
    <attribute3 />
</item>

如何修复我的 CustomElement 类,以免丢失值?

【问题讨论】:

  • 您正在序列化一个没有数据的类的实例。所以将数据添加到类的实例中。
  • @jdweng 该类内部确实有数据,由该代码 sn-p 之外的代码设置。
  • 你确定吗?错误消息另有说明。我怀疑你有两个类的实例,你试图序列化一个空的而不是包含数据的。
  • 我检查了调试器,里面肯定有数据。

标签: c# xml xmlserializer


【解决方案1】:

这里有几个问题:

  1. 您试图将XmlValue 成员序列化为为CustomElement&lt;T&gt; 实例生成的元素的元素值,但您已将其定义为只读 expression-bodied member

    public T XmlValue => Value;
    

    XmlSerializer 只会序列化公共读/写属性和字段,因此您必须添加一个 setter 和一个 getter:

    [XmlText]
    public T XmlValue { get => Value; set => Value = value; }
    

    或者,为了简化您的模型,您可以完全消除XmlValue,并通过用[XmlText] 标记来直接序列化Value。 XML 序列化属性可以应用于字段和属性。

  2. 当基础值为null 时,您正试图使用​​{propertyName}Specified pattern 抑制&lt;something&gt; 元素的序列化。此模式主要用于跟踪是否遇到关联元素,因此xxxSpecified 属性必须用[XmlIgnore] 标记:

    [XmlIgnore]
    public bool XmlSomethingSpecified => Something.HasValue;
    

    或者,由于您实际上不需要跟踪 &lt;something&gt; 元素的存在,您可以通过切换到 ShouldSerialize{PropertyName}() 模式来简化模型:

    public bool ShouldSerializeXmlSomething() => Something.HasValue;
    

    ShouldSerialize() vs Specified Conditional Serialization Pattern 中描述了两种模式之间的差异。

  3. 如果您的 Item 类型将成为 XML 文档的根元素,则必须用 [XmlRoot("item")] 标记它,以使根元素的名称为 &lt;item&gt;

    [XmlRoot("item")]
    [XmlType(TypeName = "ci")]
    public class Item
    {
        // Etc Etc
    }
    
  4. 在您的 c# 代码中,您已将 XmlSomething 属性标记为 [XmlElement],但在您的 XML 中,something 显示为 元素&lt;something&gt;true&lt;/something&gt;

    如果你真的希望它成为一个元素,你必须用[XmlElement] 标记XmlSomething

    [XmlElement("something")]
    public bool XmlSomething
    {
        get => Something != null && Something.Value;
        set => Something = value;
    }
    
  5. 在您的问题中,您展示了一个具有非布尔文本值的 &lt;something&gt; 元素示例:

    <attribute3>
        3
        <something>text</something>
    </attribute3>
    

    我认为这是问题中的拼写错误,但如果不是,您将需要重新设计您的 CustomElement&lt;T&gt; 类型以使 Something 成为 string

Roslyn .Net fiddlesecond 的工作示例以及 CustomElement&lt;T&gt; 的建议简化,以及 third,其中 &lt;something&gt; 显示为子元素。

第二把小提琴的类看起来像:

public class CustomElement<T>
{
    [XmlText]
    public T Value;

    public CustomElement()
    {
    }

    public CustomElement(T value)
    {
        Value = value;
    }

    [XmlIgnore]
    public bool? Something { get; set; }

    [XmlAttribute("something")]
    public bool XmlSomething
    {
        get => Something != null && Something.Value;
        set => Something = value;
    }

    public bool ShouldSerializeXmlSomething() => Something.HasValue;

    public static implicit operator CustomElement<T>(T x)
    {
        return new CustomElement<T>(x);
    }
}

[XmlRoot("item")]
[XmlType(TypeName = "ci")]
public class Item
{
    [XmlElement("attribute1")]
    public CustomElement<string> Attribute1 { get; set; }

    [XmlElement("attribute2")]
    public CustomElement<string> Attribute2 { get; set; }

    [XmlElement("attribute3")]
    public CustomElement<string> Attribute3 { get; set; }

    // Etc Etc
}

【讨论】:

  • 感谢您的回答。 Re 5:它不是一个类型。我的班级需要支持任何原始类型的序列化,例如boolstringdecimalDateTime。这就是为什么CustomElement 是一个泛型类。
  • @tyteen4a03 - 好的,但是在您的CustomElement&lt;T&gt; 中,您使用 元素值 的通用参数而不是 &lt;something&gt; 子元素值 .这是问题中的错误吗?该问题还有其他错误,包括无效的 XML 语法,我已修复。
  • Re 4 - 这是我的错误; something 是一个属性,而不是一个元素。
  • 不,&lt;attribute*s&gt; 的值映射到CustomElement&lt;T&gt;::Value。该值最终将是一个字符串,但我需要一种在序列化时透明地格式化DateTimes 的方法,所以这是我想出的解决方案。该自定义行为在CustomElement&lt;T&gt; 的子类中定义,此处未显示。
  • @tyteen4a03 - 我无法回答有关您未显示的内容的问题。在您实际显示的内容中,XmlSomething 被硬编码为bool。无论如何,如何修复我的CustomElement 类以使值不会丢失? 的问题是否得到回答?如果是这样,您可能想问另一个问题,因为首选格式是 one question per post
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-03-10
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多