c # логическая проблема сериализации - PullRequest
0 голосов
/ 31 октября 2018

У меня есть значение, которое я хотел бы десериализовать как логическое значение, но десериализация не поддерживает данный случай, а именно: FALSE или TRUE, и предоставленный формат будет громоздким для изменения, я получаю исключение :

System.FormatException: The string 'FALSE' is not a valid Boolean value.

Это я знаю, потому что сериализатор XML не поддерживает это; разрешены только допустимые значения схемы XML, такие как «false» или «true» (1-й бит исследования, проверьте!).

Итак, первая альтернатива - создать строковое свойство для преобразования, что-то вроде этого:

public class MyExample
{
    [XmlIgnore] public bool _booleanField { get; set; }

    [XmlElement("BooleanField")]
    public string BooleanFieldString
    {
        get => _booleanField.ToString().ToLower();
        set => _booleanField = ConvertBooleanStringValue(value);
    }

    private bool ConvertBooleanStringValue(string booleanAsString)
    {
        switch (booleanAsString.ToUpper())
        {
            case "TRUE":
            case "T":
            case "1":
            case "Y":
            case "YES":
                return true;
            case "FALSE":
            case "F":
            case "0":
            case "N":
            case "NO":
                return false;
            default:
                return false;
        }
    }
}

Но мне это не нравится, потому что это портит чистые классы, которые я построил, и должно было бы охватить это всеми логическими значениями, которые у меня есть в 28 классах (2-й бит исследования, проверьте!).

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

Я мог бы реализовать интерфейс ISerializable и написать конкретную реализацию, но это большая работа для логического значения, и из проведенного мною исследования я не уверен, что есть способ сделать это только для конкретного свойства что, очевидно, ограничит боль (третий бит исследования !!!).

Существуют другие среды сериализации, которые могут разрешать эту проблему, например ExtendedXmlSerializer, но я бы предпочел придерживаться того, что я знаю, если это возможно.

1 Ответ

0 голосов
/ 31 октября 2018

При условии, что вы можете определить все логические элементы, которым требуется эта альтернативная процедура синтаксического анализа, вы можете реализовать пользовательский XmlTextReader и передать его обычному XmlSerializer.

CustomXmlReader ниже принимает список имен элементов XML, которые требуют особого внимания.

public class CustomXmlReader : XmlTextReader
{
    private readonly IList<String> _booleanFieldNames;
    private Boolean _parseBooleanString;

    public CustomXmlReader(IList<String> booleanFieldNames, TextReader reader) : base(reader)
    {
        this._booleanFieldNames = booleanFieldNames;
    }        

    public override XmlNodeType MoveToContent()
    {            
        XmlNodeType nodeType = base.MoveToContent();            
        this._parseBooleanString = ((XmlNodeType.Element == nodeType)
            && this._booleanFieldNames.Contains(this.Name)
            );            
        return nodeType;
    }        

    public override String ReadString()
    {
        String value = base.ReadString();                        
        if (this._parseBooleanString)
        {                
            if (value.Equals("TRUE", StringComparison.OrdinalIgnoreCase)
                || value.Equals("T", StringComparison.OrdinalIgnoreCase)
                || value.Equals("1", StringComparison.OrdinalIgnoreCase)
                || value.Equals("YES", StringComparison.OrdinalIgnoreCase)
                || value.Equals("Y", StringComparison.OrdinalIgnoreCase)
                )
            { 
                return "true";                        
            }

            return "false";                
        }

        return value;
    }
}

Классы, соответствующие xml, не знают об этом пользовательском анализе.

public class MyExample
{
    public MyExample() {}

    [XmlElement("BooleanField")]
    public Boolean BooleanFieldString { get; set; }
}

Код ниже анализирует следующую структуру xml

const String XML = @"
    <MyExample>
        <BooleanField>T</BooleanField>
    </MyExample>";

using (var stringReader = new StringReader(XML))
using (var xmlReader = new CustomXmlReader(new List<String> { "BooleanField" }, stringReader))
{
    XmlSerializer serializer = new XmlSerializer(typeof(MyExample));
    MyExample mx = serializer.Deserialize(xmlReader) as MyExample;
    Console.WriteLine(mx.BooleanFieldString); // True
}
...