【问题标题】:c# the boolean serialization issuec# 布尔序列化问题
【发布时间】:2019-04-04 14:45:56
【问题描述】:

我有一个值我想反序列化为布尔值,但反序列化不支持给定的情况,即:FALSE 或 TRUE,并且提供的格式更改起来很麻烦,我得到一个抛出异常:

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

我知道这是因为 XML 序列化器不支持这个;只允许使用有效的 XML 模式值,例如“false”或“true”(第一次研究,检查!)。

所以,第一种选择是创建一个字符串属性来进行转换,如下所示:

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 个类中拥有的所有布尔值(第二位研究,检查!)。

我收到的 XML 可能会为各种参数传递大量布尔值,因此如果我选择解析源数据,我需要知道所有布尔元素是哪些。这里的限制是 XMLSerialiser,虽然这不是它的错,但我明白了。

我可以实现 ISerializable 接口并编写一个特定的实现,但是对于布尔值来说这是很多工作,而且根据我所做的研究,我不相信有一种方法可以只针对特定属性执行此操作这显然会限制痛苦(第三位研究!!!)。

还有其他序列化框架,可以像 ExtendedXmlSerializer 那样解决这个问题,但如果可能的话,我宁愿坚持我所知道的。

【问题讨论】:

  • ConvertBooleanStringValue 返回一个布尔值。所以,set => _booleanField = ConvertBooleanStringValue(value); 这一行令人困惑。
  • 您可以通过简单地将此方法重构为所有属性设置器都可以调用的静态实用程序类来大大降低成本。但是仍然需要实现属性和调用方法。
  • 这里真的有问题吗?
  • 可能有点容易出错,但根据应用程序,我可能会添加一个设置“允许旧版 xml 格式”并在 "FALSE">FALSE</ 上使用 string.Replace 和其他值。不过,这对于数值可能不是一个好主意
  • (单独)负责序列化,还是你需要反序列化从你无法控制的地方获得的数据?

标签: c# boolean deserialization


【解决方案1】:

在您可以识别需要此替代解析例程的所有布尔元素的前提下,您可以实现自定义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
}

【讨论】:

    猜你喜欢
    • 2019-09-14
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-02-01
    • 2016-09-11
    相关资源
    最近更新 更多