I've got a few classes and structures that I use XML serialization to save 开发者_运维百科and recall data, but a feature that I'd like to have is to output integers in hex representation. Is there any attribute that I can hang on these structure to make that happen?
There's a bit of code smell, but the following will work:
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);
}
}
}
Test the class in a console program:
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();
}
}
The result:
<?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>
I know, last answer was more than two years ago, but I was looking for have a solution and found this thread. But wasn't satisfied by proposed solutions so I tried to find my own solution:
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); }
}
Now you can use this type instead of Int32 in your serialized class :
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());
}
The result is :
<?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>
You can adapt the solution to get the exact format you want and complete the HInt32 struct to be more "Int32 complient". Warning : This solution can't be use to serialize a property as an attribute.
You can implement fully custom serialization, but that's probably a bit much for this. How about exposing a property MyIntegerAsHex
, that returns the integer as a string, formatted as a hexadecimal number: MyInteger.ToString("X");
The property will need a setter, even though it's a calculated field, so that the string from the serialized object can be fed into a new instance on deserialization.
You can then implement a deserialization callback, or just put code in the setter, that will parse the hex number to a decimal integer when the object is deserialized: MyInteger = int.Parse(IntegerAsHex, NumberStyles.AllowHexNumber);
So, in summary, your property would look something like this:
public string MyIntegerAsHex
{
get { return MyInteger.ToString("X"); }
set { MyInteger = int.Parse(value, NumberStyles.AllowHexNumber); }
}
Then, if you didn't want to see the number as a decimal integer in the XML file, just tag it with [XmlIgnore].
I came up with a slightly improved variant of the workaround from KeithS and 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);
}
}
}
The benefit of this is that the xsd.exe tool will set the type attribute to xs:hexBinary
instead of 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>
精彩评论