强制 XML 序列化以序列化只读属性

问题描述 投票:0回答:5

在 C# 中,我有一个类,它有一个应该通过 XML 序列化的派生属性。但是,XML 序列化(默认情况下)不会序列化 read=only 属性。我可以通过像这样定义一个空的 setter 来解决这个问题:

public virtual string IdString
{
    get { return Id.ToString("000000"); }
    set { /* required for xml serialization */ }
}

但是除了编写我自己的 ISerializable 实现之外,是否有更清晰、语义上更正确的方法?

c# xml-serialization
5个回答
20
投票

老实说,只要有记录,这对我来说似乎还不错

如果实际调用了 setter,您可能应该抛出异常:

/// <summary>
/// Blah blah blah.
/// </summary>
/// <exception cref="NotSupportedException">Any use of the setter for this property.</exception>
/// <remarks>
/// This property is read only and should not be set.  
/// The setter is provided for XML serialisation.
/// </remarks>
public virtual string IdString
{
    get
    {
        return Id.ToString("000000");
    }
    set
    {
        throw new NotSupportedException("Setting the IdString property is not supported");
    }
}

14
投票

简而言之,没有。使用

XmlSerializer
,您可以实现
IXmlSerializable
(这是非常重要的),或者编写一个基本的 DTO(完全读写),然后从 DTO 模型转换为您的主模型。

请注意,在某些情况下

DataContractSerializer
是一个可行的选项,但它不提供对 XML 的相同控制。但是,使用 DCS,您可以:

[DataMember]
public int Id { get; private set; }

6
投票

使用 C# 8,允许废弃

set
,因此您可以这样做:

public virtual string IdString
{
    get { return Id.ToString("000000"); }
    [Obsolete("Only used for xml serialization", error: true)]
    set { throw new NotSupportedException(); }
}

如果有人不小心使用了设置器,这将出错。


1
投票

进一步解决问题,让反序列化也能正常工作……

public class A
{
    private int _id = -1;

    public int Id
    {
        get { return _id; }
        set
        {
            if (_id < 0)
                throw new InvalidOperationException("...");

            if (value < 0)
                throw new ArgumentException("...");

            _id = value;
        }
    }
}

这将允许

Id
被恰好设置为大于或等于 0 的值一次。之后任何尝试设置它都会导致
InvalidOperationException
。这意味着
XmlSerializer
将能够在反序列化期间设置
Id
,但之后将永远无法更改。请注意,如果该属性是引用类型,那么您只需检查是否为 null。

如果您有很多只读属性要序列化/反序列化,这可能不是最佳解决方案,因为它需要大量样板代码。但是,我发现这对于具有 1-2 个只读属性的类来说是可以接受的。

仍然是 hack,但这至少 little 更强大。


0
投票

在大多数情况下,当我们定义一个只读属性时,它们必须在序列化中被忽略。所以只是简单地忽略它们:

public class Classname
{
    [JsonIgnore]
    [XmlIgnore]
    public virtual string IdString { get; private set; }
}
© www.soinside.com 2019 - 2024. All rights reserved.