如何在.NET中自定义JSON枚举的反序列化?

时间:2012-01-25 08:32:23

标签: c# wcf json xsd datacontractserializer

我有以下使用svcutils.exe应用程序从xsd自动生成的C#代码示例。

    [DataContract]
    public enum Foo
    {
        [EnumMember(Value = "bar")]
        Bar = 1,

        [EnumMember(Value = "baz")]
        Baz = 2
    }

    [DataContract]
    public class UNameIt
    {
        [DataMember(Name = "id")]
        public long Id { get; private set; }

        [DataMember(Name = "name")]
        public string Name { get; private set; }

        [DataMember(Name = "foo")]
        public Foo Foo { get; private set; }
    }

以下是单元测试,尝试将示例JSON文档反序列化为UNameIt类。

    [TestClass]
    public class JsonSerializer_Fixture
    {
        public const string JsonData = @"{ ""id"":123456,
                                           ""name"":""John Doe"",
                                           ""foo"":""Bar""}";

        [TestMethod]
        public void DataObjectSimpleParseTest()
        {
            DataContractJsonSerializer serializer = new DataContractJsonSerializer(typeof(UNameIt));

            MemoryStream ms = new MemoryStream(Encoding.Unicode.GetBytes(JsonData));
            UNameIt dataObject = serializer.ReadObject(ms) as UNameIt;

            Assert.IsNotNull(dataObject);
            Assert.AreEqual(123456, dataObject.Id);
            Assert.AreEqual(Foo.Baz, dataObject.Foo);
        }
    }

不幸的是,测试失败的原因如下:

  

System.Runtime.Serialization.SerializationException:有一个   错误反序列化MyNamespace.Units.UNameIt类型的对象。该   值'Bar'无法解析为'Int64'类型。

如果我更新我的JSON字符串以将Enum的字符串说明符替换为整数,则测试将通过。

public const string JsonData = @"{ ""id"":123456,
                                   ""name"":""John Doe"",
                                    ""foo"":""1""}";

我没有更改提供的JSON的灵活性,所以我必须弄清楚如何在序列化时转换字符串Enum表示。理想情况下,我想在不必更改自动生成类的情况下为此提供帮助,因为一旦我重新生成类,我就会失去我的更改。

我想知道是否可以将DataContractJsonSerializer扩展为自定义句柄枚举?或者也许有更好的方法来做到这一点?

2 个答案:

答案 0 :(得分:6)

此行为按设计。以下是Enumerations and JSON paragraph on MSDN

的引用
  

枚举成员值被视为JSON中的数字,即   不同于它们在数据合同中的处理方式   作为会员名称加入。

此外,DataContractJsonSerializer会自动序列化所有枚举,因此EnumMemberAttribute实际上会被忽略。

对于解决方法,请查看this answer on SO

答案 1 :(得分:0)

这是工作:

var ret = new JavaScriptSerializer().Deserialize<tblGridProjects>(retApi.Item2);

但是您无法使用数据名称属性,因此无法重命名属性。 您必须设置Json发送的属性名称。