【问题标题】:XmlSerializer: How to Deserialize an enum value that no longer existsXmlSerializer:如何反序列化不再存在的枚举值
【发布时间】:2012-05-29 07:27:12
【问题描述】:

我正在使用 XMLSerializer 将此类保存到文件中。该类有一个字符串和一个枚举,如下所示:

public class IOPoint
{
     string Name {get; set;}
     TypeEnum {get; set;}
}


public enum TypeEnum
{
    Temperature,
    Pressure,
    Humidity,
}

序列化后看起来像这样。

<IOPoint>
  <Name>Relative Humidity</Name>
  <TypeEnum>Humidity</TypeEnum>
</IOPoint>

我一直在序列化和反序列化这个对象,几个版本都没有问题。我不再想支持 Humidity,所以我从枚举中删除了它。但是,当从 XML 反序列化时,这会导致异常,因为 TypeEnum 字段中的值 Humidity 不是 TypeEnum 的有效值。这是有道理的,但是如何处理呢?

我想做的就是忽略这个错误。并将值保留为空。我已经尝试实现 OnUnknownElement XmlDeserilizationEvent 类。不幸的是,这并没有捕捉到这个错误。

关于如何捕获和忽略此错误的任何想法(我可以在反序列化完成后进行清理)。

米奇

【问题讨论】:

  • 如果您找到了我很想知道的解决方案。我有一个相关的问题,服务器端包含一个客户端不知道的新枚举标志值,所以真的想找到一种方法来管理那个字段的序列化。下次我将只使用 int,但现在……向后兼容。

标签: c# xml serialization versioning deserialization


【解决方案1】:

您可以将会员标记为作废

public enum TypeEnum
{
    Temperature,
    Pressure,
    [Obsolete]
    Humidity
}

【讨论】:

  • 我不能使用 [Obsolete] 属性的原因是我们的代码中的常见做法是遍历枚举值。所以即使“湿度”被标记为过时,它仍然会在我们的 foreach 循环中被选中。 (除非有办法覆盖枚举器?)
  • 无论您在哪里使用变量,都可以将其设为 null 吗?例如,类型枚举? val = null;
【解决方案2】:

在您的库已在使用后删除枚举成员通常被认为是不好的做法。为什么不将成员留在原处,而是用[Obsolete] 属性标记它以防止将来使用?将 ObsoleteAttribute(string,bool) 构造函数的第二个参数指定为 true 如果访问标记的成员会导致编译时错误。

public enum TypeEnum
{
    Temperature,
    Pressure,

    [Obsolete("It's always sunny in Philadelphia", true)]
    Humidity,
}

为了在检查反序列化值时规避错误,您可以与基础值进行比较:typeEnum == (TypeEnum)2

【讨论】:

    【解决方案3】:

    您可以实现IXmlSerializable,您可以在其中对枚举使用 TryParse 之类的东西。

    但我同意其他使用过时属性的海报。

    【讨论】:

    • 如果我找不到其他解决方法,使用 IXMLSerializable 进行自定义序列化是唯一的解决方案。当我这样做时,我还会添加一个版本字段,我可以使用它来指导反序列化。我们在使用 ISerializable 时会做类似的事情。真正的类有大约 15 个字段。我想知道我是否可以只为一个字段编写反序列化代码?
    【解决方案4】:

    您可以使用属性来更改节点名称并从 xml 序列化中隐藏元素,手动解析一个元素:

    public class IOPoint
    {
     public string Name {get; set;}
    
     [XmlIgnore]
     public TypeEnum TypeEnum {get; set;}
    
     [XmlElement("TypeEnum")]
     public string LegacyTypeEnum 
     {
      get { return this.TypeEnum.ToString(); }
      set 
      { 
       try
       {
        this.TypeEnum = (TypeEnum)Enum.Parse(typeof(TypeEnum),value);
       }
       catch(ArgumentException)
       {
        // Handle "Humidity"
       }
       catch(OverflowException)
       {
       }
      }
     }
    }
    

    每厘米似乎有些混乱; here is a worked example 作为 Visual Studio 2010 项目。这种方法是一种仅手动解析对象的一个​​属性的简单方法(仍然利用 XmlSerializer 进行 XML 解析)。

    【讨论】:

    • 将枚举值序列化为字符串而不是枚举,如果我还没有需要读取的 XML 文件,这将是一个好主意。这些现有文件具有 元素,我仍然需要读取 TypeEnum 字段的值并采取相应措施。理想的解决方案是在尝试反序列化 Humidity 值时捕获异常。但是你放在反序列化器上的异常处理程序都没有捕捉到这个错误。
    • 我已经包含了一个可编译的示例来演示它的工作原理和工作原理。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-05-31
    • 2015-07-26
    • 1970-01-01
    相关资源
    最近更新 更多