Как вывести шестнадцатеричные числа с помощью XML-сериализации в C #? - PullRequest
5 голосов
/ 01 октября 2010

У меня есть несколько классов и структур, которые я использую сериализацию XML для сохранения и вызова данных, но мне хотелось бы иметь возможность выводить целые числа в шестнадцатеричном представлении. Есть ли какой-нибудь атрибут, который я могу повесить на эту структуру, чтобы это произошло?

Ответы [ 4 ]

4 голосов
/ 01 октября 2010

Есть небольшой запах кода, но следующее будет работать :

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>
1 голос
/ 22 января 2013

Я знаю, последний ответ был более двух лет назад, но я искал решение и нашел эту ветку. Но предложенные решения не удовлетворили меня, и я попытался найти собственное решение:

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-совместимой". Предупреждение: это решение нельзя использовать для сериализации свойства как атрибута.

1 голос
/ 01 марта 2012

Я придумал немного улучшенный вариант обходного пути из 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инструмент установит атрибут типа 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>
1 голос
/ 01 октября 2010

Вы можете реализовать полностью настраиваемую сериализацию, но это, вероятно, немного для этого.Как насчет предоставления свойства 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].

...