我有一些类和结构,我使用 XML 序列化来保存和调用数据,但我想要的一个功能是以十六进制表示形式输出整数。有什么属性可以挂在这些结构上来实现吗?
4 回答
有一点代码异味,但以下将起作用:
public class ViewAsHex
{
[XmlIgnore]
public int Value { get; set; }
[XmlElement(ElementName="Value")]
public string HexValue
{
get
{
// convert int to hex representation
return Value.ToString("x");
}
set
{
// convert hex representation back to int
Value = int.Parse(value,
System.Globalization.NumberStyles.HexNumber);
}
}
}
在控制台程序中测试类:
public class Program
{
static void Main(string[] args)
{
var o = new ViewAsHex();
o.Value = 258986522;
var xs = new XmlSerializer(typeof(ViewAsHex));
var output = Console.OpenStandardOutput();
xs.Serialize(output, o);
Console.WriteLine();
Console.WriteLine("Press enter to exit.");
Console.ReadLine();
}
}
结果:
<?xml version="1.0"?>
<ViewAsHex xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<Value>f6fd21a</Value>
</ViewAsHex>
我知道,最后一个答案是两年多前,但我一直在寻找解决方案并找到了这个线程。但对提出的解决方案不满意,所以我试图找到自己的解决方案:
public struct HInt32 : IXmlSerializable
{
private int _Value;
public HInt32(int v) { _Value = v; }
XmlSchema IXmlSerializable.GetSchema() { return null; }
void IXmlSerializable.ReadXml(XmlReader reader) { _Value = Int32.Parse(reader.ReadContentAsString().TrimStart('0', 'x'), NumberStyles.HexNumber); }
void IXmlSerializable.WriteXml(XmlWriter writer) { writer.WriteValue("0x" + _Value.ToString("X2").PadLeft(8, '0')); }
public static implicit operator int(HInt32 v) { return v._Value; }
public static implicit operator HInt32(int v) { return new HInt32(v); }
}
现在您可以在序列化类中使用这种类型而不是 Int32 :
public TestClass
{
public HInt32 HexaValue { get; set; }
}
public void SerializeClass()
{
TestClass t = new TestClass();
t.HexaValue = 6574768; // Transparent int assigment
XmlSerializer xser = new XmlSerializer(typeof(TestClass));
StringBuilder sb = new StringBuilder();
using(StringWriter sw = new StringWriter(sb))
{
xser.Serialize(sw, t);
}
Console.WriteLine(sb.ToString());
}
结果是:
<?xml version="1.0" encoding="utf-16"?>
<TestClass xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<HexaValue>0x006452B0</HexaValue>
</TestClass>
您可以调整解决方案以获得所需的确切格式,并完成 HInt32 结构以更加“符合 Int32”。警告:此解决方案不能用于将属性序列化为属性。
我从KeithS和code4life提出了一个稍微改进的变通方法。
using System;
using System.Linq;
public class Data
{
[XmlIgnore()]
public uint Value { get; set; }
[XmlAttribute("Value", DataType = "hexBinary")]
public byte[] ValueBinary
{
get
{
return BitConverter.GetBytes(Value).Reverse().ToArray();
}
set
{
Value = BitConverter.ToUInt32(value.Reverse().ToArray(), 0);
}
}
}
这样做的好处是 xsd.exe 工具会将 type 属性设置xs:hexBinary
为xs:string
...
<?xml version="1.0" encoding="utf-8"?>
<xs:schema elementFormDefault="qualified" xmlns:xs="http://www.w3.org/2001/XMLSchema">
<xs:element name="Data" nillable="true" type="Data" />
<xs:complexType name="Data">
<xs:attribute name="Value" type="xs:hexBinary" />
</xs:complexType>
</xs:schema>
您可以实现完全自定义的序列化,但这可能有点多。公开一个属性如何MyIntegerAsHex
,它将整数作为字符串返回,格式为十六进制数:MyInteger.ToString("X");
该属性将需要一个设置器,即使它是一个计算字段,以便可以将来自序列化对象的字符串输入到一个新实例中反序列化。
然后,您可以实现反序列化回调,或者只是将代码放入设置器中,当对象被反序列化时,它将十六进制数解析为十进制整数:MyInteger = int.Parse(IntegerAsHex, NumberStyles.AllowHexNumber);
因此,总而言之,您的属性将如下所示:
public string MyIntegerAsHex
{
get { return MyInteger.ToString("X"); }
set { MyInteger = int.Parse(value, NumberStyles.AllowHexNumber); }
}
然后,如果您不想在 XML 文件中将数字视为十进制整数,只需用 [XmlIgnore] 标记它。