【问题标题】:Deserialize Enum from Xml using Value property in c#使用 c# 中的 Value 属性从 Xml 反序列化枚举
【发布时间】:2013-02-21 12:54:21
【问题描述】:

我正在尝试用 C# 编写一个用于书籍导入工具的 ONIX。我首先使用 Xsd2Code 创建类,并获得了一个包含所有属性的巨大文件,经过一些调整后在反序列化时不会产生任何错误。

我正在尝试一次将整个元素反序列化为内存中的一个大对象,然后对其进行处理(例如将其保存到数据库中)。

Xsd2Code 生成类的方式,除了有很多属性之外,有点奇怪,至少对我来说是这样。

这是应该是 Product 对象属性的类之一:

public partial class NotificationType
{
    public NotificationTypeRefname refname { get; set; }
    public NotificationTypeShortname shortname { get; set; }

    public SourceTypeCode sourcetype { get; set; }

    public List1 Value { get; set; }
}

我想请您注意这一行:

    public List1 Value { get; set; }

“List1”是一个枚举,定义如下:

public enum List1
{
    [System.Xml.Serialization.XmlEnum("01")]
    Item01,

    [System.Xml.Serialization.XmlEnum("02")]
    Item02, etc...

我的问题是,在反序列化过程中,所有字段都正确反序列化,除了枚举。

我尝试用 XmlEnum("NotificationType") 等装饰属性...什么也没有!

这是我的反序列化代码:

var p = new Product();
XmlSerializer pserializer = new XmlSerializer(p.GetType());
object pDeserialized = pserializer.Deserialize(reader);
p = (Product) pDeserialized;

这是这个元素在 XML 中的样子:

<NotificationType>03</NotificationType>

C# 中 Product 对象的属性是:

public NotificationType NotificationType { get; set; }

如果我将其更改为:

public List1 NotificationType { get; set; }

反序列化正确显示“Item03”,这意味着它确实读取了 XML 中的任何内容。如果我像上面那样保留它,NotificationType 类的“Value”属性永远不会被填充,并且总是显示 Item01(Enum 的默认值)。

关于为什么这个 Value 属性适用于某些类型(字符串)但不适用于枚举,我已经用尽了关于 SO 和网络搜索的所有可能问题。我错过了什么吗?

抱歉,问题和代码太长了。感谢任何人都可以在这个问题上阐明的任何观点。已经坚持了一整天了。

【问题讨论】:

    标签: c# xml enums deserialization


    【解决方案1】:

    试试这个:

    public partial class NotificationType
    {
        public NotificationTypeRefname refname { get; set; }
        public NotificationTypeShortname shortname { get; set; }
        public SourceTypeCode sourcetype { get; set; }
    
        public List1 Value { get {
            return (List1)Enum.Parse(typeof(List1), 
                Enum.GetName(typeof(List1), int.Parse(List1Value) - 1));
        }}
    
        [XmlText]
        public string List1Value { get; set; }
    }
    

    [更新]

    自:

    1. 我一开始也尝试用XmlText属性装饰成员,但出现以下异常:

      无法序列化类型的对象 'ConsoleApplication1.NotificationType'。考虑改变类型 XmlText 成员“ConsoleApplication1.NotificationType.Value”来自 ConsoleApplication1.List1 为字符串或字符串数​​组。

    2. 你想避免我在回答中的初始方法,

    真正的解决方案是,除了将XmlText 属性应用于Value 之外,所有其他成员都应使用XmlIgnoreAttribute 进行装饰。我认为单独使用XmlText 并不能保证解决方案,因为结果取决于其他成员的存在。

    public class NotificationType
    {
        [XmlIgnore] // required
        public NotificationTypeRefname refname { get; set; }
        [XmlIgnore] // required
        public NotificationTypeShortname shortname { get; set; }
        [XmlIgnore] // required
        public SourceTypeCode sourcetype { get; set; }
    
        [XmlText] // required
        public List1 Value { get; set; }
    }
    

    【讨论】:

    • 投了赞成票,这也有效,但方式不那么直接。我真的不喜欢为每种情况引入额外的属性,因为 ONIX 规范中大约有 200 个。
    • @CristiCotovan,当我尝试 pbz 的答案时,我也有一个 InvalidOperationException。他的回答是我第一次尝试,但失败了(而且仍然失败),所以我寻找了解决方法。
    • 它在这里工作,我不知道为什么它对你来说失败了。我更喜欢这种方式,因为它更简洁,并且我在顶部添加了其他内容(例如描述每个 Enum 变体并使用反射提取它以显示每个 Enum 值的用户友好含义)。
    • 现在只是想弄清楚,是的,您的更新确实有效。如果不忽略那些其他属性。我忘记了我第一次检查这些属性时被注释掉了。干得好!
    • 您的最后一次更新与同一个类中有两个属性需要从 XML 反序列化的情况不同,就像我刚刚遇到的情况一样。一个类包含两个属性: public List74 language { get;放; } 和公共字符串值 { 获取;放; }
    【解决方案2】:

    尝试将[System.Xml.Serialization.XmlTextAttribute()] 添加到public List1 Value { get; set; } 属性。

    【讨论】:

    • 这行得通!我可以发誓我以前试过。我认为这是让反序列化库知道要填充什么属性作为 XML 元素的值的属性。
    • 疯了,我也在做ONIX!对于单个 Enum 值,同样的事情对我也很有效。对枚举数组进行反序列化有什么运气吗?比如 List91[] ?
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-04-14
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多