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

本文关键字:JSON 枚举 反序列化 自定义 NET | 更新日期: 2023-09-27 18:21:25

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

    [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.Serialization异常:存在反序列化MyNamespace.Units.UNameIt类型的对象时出错值"Bar"无法解析为类型"Int64"。

如果我更新JSON字符串以将枚举的字符串说明符替换为整数(例如),则测试将通过

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

我没有灵活性来更改提供的JSON,所以我必须弄清楚如何转换字符串Enum表示——也许是串行化。理想情况下,我希望在不必更改自动生成类的情况下实现这一点,因为一旦重新生成类,我就会丢失更改。

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

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

此行为是设计的。下面引用MSDN上的枚举和JSON段落:

枚举成员值在JSON中被视为数字与数据合同中对待它们的方式不同,它们在哪里包含为成员名称。

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

对于解决方法,请查看SO上的此答案。

这就是工作:

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

但是您不能使用datamembers属性,因此不能重命名属性。您必须像Json sended那样设置属性的名称。