XmlSerializer: 如何反序列化一个不存在的枚举值

9

我正在使用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>

我已经连续几个版本对这个对象进行序列化和反序列化,没有出现任何问题。我不再想支持湿度,所以我将其从枚举中删除了。然而,在从XML反序列化时,这会导致异常,因为TypeEnum字段中的值Humidity不是TypeEnum的有效值。这很合理,但如何处理呢?
我想要做的就是忽略这个错误。并将值保留为空。我尝试实现OnUnknownElement XmlDeserilizationEvent类。不幸的是,这并不能捕获此错误。
有没有关于如何捕获和忽略此错误的想法(我可以在反序列化完成后清理)。
米奇

如果你找到了解决方案,我很想知道。我有一个相关的问题,即服务器端包含一个客户端不知道的新枚举标志值,因此真正希望找到一种管理仅该字段序列化的方法。下次我会使用int,但现在需要考虑向后兼容性。 - avenmore
4个回答

5
您可以将该成员标记为已过时。
public enum TypeEnum
{
    Temperature,
    Pressure,
    [Obsolete]
    Humidity
}

2
我不能使用[Obsolete]属性的原因是,我们的代码通常会遍历枚举值。因此,即使“Humidity”被标记为过时,它仍然会在我们的foreach循环中被捕获。(除非有一种方法可以覆盖枚举器?) - Mitch
你能否在使用变量的任何地方将其设置为null? 例如,TypeEnum?val = null; - user3362735

4

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

public enum TypeEnum
{
    Temperature,
    Pressure,

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

为了避免在检查反序列化值时出错,您可以与底层值进行比较:typeEnum == (TypeEnum)2

2

您可以使用属性来更改节点名称并从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)
   {
   }
  }
 }
}

根据评论,似乎存在一些混淆; 这里有一个示例,作为Visual Studio 2010项目。这种方法是手动解析对象的一个属性的简单方法(仍然利用XmlSerializer进行XML解析)。


如果我没有需要读取的XML文件,将枚举值序列化为字符串而不是枚举会是一个好主意。这些现有文件具有<TypeEnum>元素,我仍然需要读取TypeEnum字段的值并相应地采取措施。理想的解决方案是在尝试反序列化湿度值时捕获异常。但是,您放在反序列化程序上的任何异常处理程序都无法捕获此错误。 - Mitch
我已经包含了一个可编译的示例来展示它是如何工作的,以及它是如何工作的。 - user423430

1

您可以实现 IXmlSerializable,在其中可以使用类似于 TryParse 的方法来处理枚举。

但我同意其他帖子中使用过时属性的做法。


如果我找不到其他解决方法,使用IXMLSerializable进行自定义序列化可能是唯一的解决方案。在此过程中,我还会添加一个版本字段,以便在反序列化时使用。当使用ISerializable时,我们也会执行类似的操作。实际类有大约15个字段。我想知道是否可以只编写一个字段的反序列化器代码? - Mitch

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接