У меня есть несколько классов и структур, в которых я использую сериализацию XML для сохранения и воспроизведения данных, но функция, которую я хотел бы иметь, состоит в выводе целых чисел в шестнадцатеричном представлении. Есть ли какой-либо атрибут, который я могу повесить на эту структуру, чтобы это произошло?Как выводить шестнадцатеричные числа через XML-сериализацию в C#?
ответ
Вы можете реализовать полностью пользовательскую сериализацию, но это, вероятно, немного для этого. Как об экспонировании свойства 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].
Там есть немного кода запаха, но следующий будет работы:
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>
Я придумал несколько улучшенный вариант обходного пути от KeithS и код4life.
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 будет установлен атрибут типа для 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>
Я знаю, последний ответ был более двух лет назад, но я искал решение и нашел эту тему. Но не была удовлетворена предлагаемыми решениями, поэтому я пытался найти свое собственное решение:
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 complient». Предупреждение. Это решение не может использоваться для сериализации свойства как атрибута.
Я использовал этот подход. Хотя это немного запах, прост в чтении хорошо работает. – rolls