XML反序列化 - 抛出自定义错误

时间:2012-05-07 21:22:37

标签: c# xml xml-deserialization

所以我有以下方法:

private int? myIntField
[System.Xml.Serialization.XmlElementAttribute(Form = System.Xml.Schema.XmlSchemaForm.Unqualified)]
public int? IntField{
    get {
        return this.myIntField;
    }
    set {
        this.myIntField= value;
    }
 }

现在,我正在从帖子反序列化xml,如果由于某种原因我得到一个字符串,例如“这里是int字段:55444”而不是55444,我得到的错误是:{{1}这不是非常具体,特别是考虑到我需要验证多个int字段。

最初,我正在计划这样的事情:

Input string was not in a correct format.

CheckValue对Int32执行private string myIntField [System.Xml.Serialization.XmlElementAttribute(Form = System.Xml.Schema.XmlSchemaForm.Unqualified)] public int? IntField{ get { return this.myIntField.CheckValue(); } set { this.myIntField= value; } } ,如果失败,则返回null并向列表添加错误。但是,我似乎无法确定生成的类的这个设置。

如果我在获取字符串代替整数,DateTimes等时,我是否可以抛出特定错误?

3 个答案:

答案 0 :(得分:4)

如果您有XML架构并在反序列化之前根据架构验证它,那么很容易。假设您有XML的架构,您可以初始化XmlSchemaSet,在其中添加架构以及:

var document = new XmlDocument();
document.LoadXml(xml); // this a string holding the XML
document.Schemas.XmlResolver = null; //if you don't need to resolve every references
document.Schemas.Add(SchemaSet); // System.Xml.Schema.XmlSchemaSet instance filled with schemas
document.Validate((sender, args) => { ... }); //args are of type ValidationEventArgs and hold problem if there is one...            

我个人认为这是一种更好的方法,因为你可以在反序列化之前验证你的XML,并确保XML是正确的,否则如果出现问题,反序列化器很可能会抛出异常并且你几乎永远无法显示对用户有意义的反馈...
附:我建议创建描述XML的模式

答案 1 :(得分:3)

“输入字符串格式不正确”消息来自调用System.FormatException引发的标准int.Parse,添加到执行反序列化的自动生成的程序集中。我认为你不能为此添加一些自定义逻辑。

一种解决方案是做这样的事情:

    [XmlElement("IntField")]
    [Browsable(false)] // not displayed in grids
    [EditorBrowsable(EditorBrowsableState.Never)] // not displayed by intellisense
    public string IntFieldString
    {
        get
        {
            return DoSomeConvert(IntField);
        }
        set
        {
            IntField = DoSomeOtherConvert(value);
        }
    }

    [XmlIgnore]
    public int? IntField { get; set; }

它并不完美,因为您仍然可以访问公共IntFieldString,但至少,“真正的”IntField属性仅以编程方式使用,而不是由XmlSerializer使用({{1 }}),而持有价值的领域&对程序员(XmlIgnore),网格(EditorBrowsable)等隐藏了第四个...但不是来自Browsable

答案 2 :(得分:2)

我有三种方法。

  • 假设您的数据是由用户在用户界面中输入的,请使用输入验证来确保数据有效。当它应该是一个整数时,允许输入随机字符串似乎很奇怪。

  • 完全按照您上面建议的方法使用。这是使用LINQ Pad

    的示例
    void Main()
    {
        using(var stream = new StringReader(
                  "<Items><Item><IntValue>1</IntValue></Item></Items>"))
        {
            var serializer = new XmlSerializer(typeof(Container));
    
            var items = (Container)serializer.Deserialize(stream);
    
            items.Dump();
        }
    }
    
    [XmlRoot("Items")]
    public class Container
    {
        [XmlElement("Item")]
        public List<Item> Items { get; set; }
    }
    
    public class Item
    {
        [XmlElement("IntValue")]
        public string _IntValue{get;set;}
    
        [XmlIgnore]
        public int IntValue
        {
            get
            {
                // TODO: check and throw appropriate exception
                return Int32.Parse(_IntValue);
            }
        }
    }
    
  • 使用IXmlSerializable控制序列化,这是另一个例子

    void Main()
    {
        using(var stream = new StringReader(
                  "<Items><Item><IntValue>1</IntValue></Item></Items>"))
        {
            var serializer = new XmlSerializer(typeof(Container));
    
            var items = (Container)serializer.Deserialize(stream);
    
            items.Dump();
        }
    }
    
    [XmlRoot("Items")]
    public class Container
    {
        [XmlElement("Item")]
        public List<Item> Items { get; set; }
    }
    
    public class Item : IXmlSerializable
    {
        public int IntValue{get;set;}
    
        public void WriteXml (XmlWriter writer)
        {
            writer.WriteElementString("IntValue", IntValue.ToString());
        }
    
        public void ReadXml (XmlReader reader)
        {
            var v = reader.ReadElementString();
            // TODO: check and throw appropriate exception
            IntValue = int.Parse(v);
        }
    
        public XmlSchema GetSchema()
        {
            return(null);
        }
    }