在C#中,我有一个类,它有一个派生属性,应该通过XML序列化。但是,XML序列化(默认情况下)不会序列化read = only属性。我可以通过定义一个空的setter来解决这个问题:
public virtual string IdString
{
get { return Id.ToString("000000"); }
set { /* required for xml serialization */ }
}
但是,如果没有编写我自己的ISerializable实现,是否有更清晰的语义更正确的方法?
答案 0 :(得分:19)
老实说,只要记录在案,这对我来说似乎并不太糟糕
如果实际调用了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");
}
}
答案 1 :(得分:14)
简而言之,没有。使用XmlSerializer
,您可以实现IXmlSerializable
(这是非平凡的),或者编写基本的DTO(完全读写),然后从DTO模型转换为主模型。
请注意,在某些情况下 DataContractSerializer
是一个可行的选项,但它不提供对XML的相同控制。但是,使用DCS,您可以:
[DataMember]
public int Id { get; private set; }
答案 2 :(得分: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个只读属性的类来说是可以接受的。
仍然是一个黑客,但这至少是小更强大。
答案 3 :(得分:1)
对于C#8,允许废弃set
,因此您可以这样做:
public virtual string IdString
{
get { return Id.ToString("000000"); }
[Obsolete("Only used for xml serialization", error: true)]
set { throw new NotSupportedException(); }
}
如果有人不小心使用了二传手,就会出错。