【问题标题】:Serializing Object With Invalid Enum Value使用无效枚举值序列化对象
【发布时间】:2012-04-15 23:27:36
【问题描述】:

我有一个 Windows Phone 7 项目,它连接到 .NET Web 服务以按需获取数据。 WP7 项目和 Web 服务都使用同一个 c# 类库的副本。这个库的一部分是EmployeeType的枚举:

Public enum EmployeeType
{
    Standard = 0,
    TeamLeader = 105
}

自从应用发布以来,Web 服务类库对其进行了更改——添加了一个新的枚举值。 (SeniorManager = 110)

因此,当我在手机上收到一个具有包含新枚举值的属性的对象时,我会在尝试将其添加到 IsolatedStorage 时得到一个 SerializationException。这是因为新的枚举值无法序列化,因为 WP7 类库没有对其进行相同的更新,并且枚举值不存在。

我想要实现的是仍然能够序列化对象,但是忽略无效的枚举值,或者用一个有效的枚举值替换它(最好是@ 987654325@)。

这将使我能够处理对 Web 服务枚举的任何未来添加,而不会破坏应用程序的功能。

注意事项:

  • 上面的枚举/值是为了问题的目的而设计的,而不是有问题的实际枚举。
  • 值将被序列化为不正确的值这一事实对于应用程序而言并不重要。

谢谢!

【问题讨论】:

  • 您是否尝试过构建自定义的 ISerializable 实现?
  • 不,我没有(也从未使用过自定义的 ISerializable 实现)。这是一个具有许多属性的大型类,所以要实现很多工作吗?另外,类上有一个 [DataContract] 属性,属性上有 [DataMember] 属性(包括枚举类型的属性),所以不确定这是否会影响什么?
  • 你不能更新到新版本的库吗?
  • @svick:是的,我可以,而且我会这样做!但是,Web 服务被多个客户端使用,而不仅仅是 WP7 项目。有时,需要对 Web 服务进行更新,我希望避免为此目的发布更新(并且 Web 服务团队希望能够在不等待 WP7 应用程序批准过程完成的情况下进行部署)。我知道这不是一个理想的情况,但我正在寻找任何有用的提示来解决这个问题,直到可以同步库。
  • 这好像是 XMLSerialization,所以 ISerializable 在这里不适用。仅适用于二进制序列化。

标签: c# serialization


【解决方案1】:

我最终使用JSON.NET 反序列化来自服务器的数据(reader 是响应流的StreamReaderTResponse 是服务器预期的通用响应。):

var serializer = new JsonSerializer();
serializer.Converters.Add(new JsonEnumTypeConverter());
this.Response = serializer.Deserialize<TResponse>(new JsonTextReader(reader));

JsonEnumTypeConverter 类检查从服务器返回的枚举值对于给定类型是否有效。如果不是,则默认为零。 (总是出现在枚举中)。该类定义如下:

private class JsonEnumTypeConverter : JsonConverter
{
    public override bool CanConvert(Type objectType)
    {
        return objectType.IsEnum;
    }

    public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
    {
        try
        {
            var value = Enum.Parse(objectType, reader.Value.ToString(), true);
            if (IsFlagDefined((Enum)value))
            {
                return value;
            }
            else
            {
                return 0;
            }
        }
        catch (Exception)
        {
            return 0;
        }
    }

    public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
    {
        writer.WriteValue(value);
    }

    private static bool IsFlagDefined(Enum e)
    {
        decimal d;
        return (!decimal.TryParse(e.ToString(), out d));
    }
}

请注意,我使用自定义 IsFlagDefined 方法,而不是 Enum.IsDefined,因为我的枚举包含 Enum.IsDefined 无法处理的 [Flags] 属性。 (来源:Enum.IsDefined with flagged enums

另外,感谢Darin Dimitrovthis question 中的回答,将我指向 JSON.NET 和 JsonConverter。

【讨论】:

  • Nit: 0 对于枚举不一定“始终存在”。
【解决方案2】:

我不明白你为什么不更新WP7项目中对WebService的引用,这样你就可以序列化它了。

无论如何,你可以试试这个workaorund:

  1. 真实字段,不被序列化

    [NonSerialized]
    public EmployeeType RealType {get; set;} 
    
  2. 一个假字段,如果 Realfield 是 SeniorManager 或实际 RealField 值,则将返回 Standard 序列化

    public EmployeeType Type 
     {
      get{
           if (RealType== EmployeeType.TeamLeader)
              return  EmployeeType.TeamLeader;
           else 
              return  EmployeeType.Standard;
         } 
      set{RealType=value;}
     }     
    

【讨论】:

  • 感谢您的回答,Emanuele。我确实评论说我将更新库,但我不想为每次更改发布应用程序更新。此外,Web 服务团队不希望在部署更改之前等待应用程序获得批准。您的回答很有趣,我很感激(+1),但我的实际枚举包含的值比我的问题示例多得多,而不仅仅是三个。我将用我如何解决它来回答我自己的问题。谢谢。
  • 您找到了一个有趣的解决方案;无论如何,我改进了 minem,以便它可以与许多 EmpoyeeType 一起使用。你也可以放一个“开关”。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2017-07-24
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2014-08-18
相关资源
最近更新 更多