首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >问答首页 >JavaScriptSerializer.Deserialize -如何更改字段名

JavaScriptSerializer.Deserialize -如何更改字段名
EN

Stack Overflow用户
提问于 2009-07-08 19:49:39
回答 8查看 103.3K关注 0票数 74

汇总:如何在使用JavaScriptSerializer.Deserialize时将JSON数据中的字段名映射到.Net对象的字段名?

更长版本的:下面的JSON数据来自服务器API (不是用.Net编写的)

代码语言:javascript
运行
复制
{"user_id":1234, "detail_level":"low"}

我有以下C#对象:

代码语言:javascript
运行
复制
[Serializable]
public class DataObject
{
    [XmlElement("user_id")]
    public int UserId { get; set; }

    [XmlElement("detail_level")]
    public DetailLevel DetailLevel { get; set; }
}

其中,DetailLevel是一个枚举,其中"Low“作为值之一。

此测试失败:

代码语言:javascript
运行
复制
[TestMethod]
public void DataObjectSimpleParseTest()
{
    JavaScriptSerializer serializer = new JavaScriptSerializer();
    DataObject dataObject = serializer.Deserialize<DataObject>(JsonData);

    Assert.IsNotNull(dataObject);
    Assert.AreEqual(DetailLevel.Low, dataObject.DetailLevel);
    Assert.AreEqual(1234, dataObject.UserId);
}

最后两个断言失败,因为在这些字段中没有数据。如果我将JSON数据更改为

代码语言:javascript
运行
复制
 {"userid":1234, "detaillevel":"low"}

然后它就过去了。但是我不能改变服务器的行为,我希望客户端类在C#成语中具有名称良好的属性。我不能使用LINQ,因为我希望它在Silverlight之外工作。看起来XmlElement标签没有任何效果。我不知道我是从哪里得到他们的相关概念的,他们可能不是。

如何在JavaScriptSerializer中进行字段名映射?完全可以做到吗?

EN

回答 8

Stack Overflow用户

发布于 2009-07-10 13:43:07

我又试了一次,使用DataContractJsonSerializer类。这解决了这个问题:

代码如下所示:

代码语言:javascript
运行
复制
using System.Runtime.Serialization;

[DataContract]
public class DataObject
{
    [DataMember(Name = "user_id")]
    public int UserId { get; set; }

    [DataMember(Name = "detail_level")]
    public string DetailLevel { get; set; }
}

而测试是:

代码语言:javascript
运行
复制
using System.Runtime.Serialization.Json;

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

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

        Assert.IsNotNull(dataObject);
        Assert.AreEqual("low", dataObject.DetailLevel);
        Assert.AreEqual(1234, dataObject.UserId);
}

唯一的缺点是,我必须将DetailLevel从枚举更改为字符串--如果您保持枚举类型不变,则DataContractJsonSerializer希望读取一个数值,但失败。有关更多细节,请参见DataContractJsonSerializer和Enum

在我看来,这是相当糟糕的,特别是在JavaScriptSerializer正确处理它的情况下。这是尝试将字符串解析为枚举的例外情况:

代码语言:javascript
运行
复制
System.Runtime.Serialization.SerializationException: There was an error deserializing the object of type DataObject. The value 'low' cannot be parsed as the type 'Int64'. --->
System.Xml.XmlException: The value 'low' cannot be parsed as the type 'Int64'. --->  
System.FormatException: Input string was not in a correct format

这样的标记并不能改变这种行为:

代码语言:javascript
运行
复制
[DataContract]
public enum DetailLevel
{
    [EnumMember(Value = "low")]
    Low,
   ...
 }

这似乎也适用于Silverlight。

票数 73
EN

Stack Overflow用户

发布于 2010-01-05 04:49:16

通过创建自定义JavaScriptConverter,您可以将任何名称映射到任何属性。但它确实需要手工编码的地图,这不是理想的。

代码语言:javascript
运行
复制
public class DataObjectJavaScriptConverter : JavaScriptConverter
{
    private static readonly Type[] _supportedTypes = new[]
    {
        typeof( DataObject )
    };

    public override IEnumerable<Type> SupportedTypes 
    { 
        get { return _supportedTypes; } 
    }

    public override object Deserialize( IDictionary<string, object> dictionary, 
                                        Type type, 
                                        JavaScriptSerializer serializer )
    {
        if( type == typeof( DataObject ) )
        {
            var obj = new DataObject();
            if( dictionary.ContainsKey( "user_id" ) )
                obj.UserId = serializer.ConvertToType<int>( 
                                           dictionary["user_id"] );
            if( dictionary.ContainsKey( "detail_level" ) )
                obj.DetailLevel = serializer.ConvertToType<DetailLevel>(
                                           dictionary["detail_level"] );

            return obj;
        }

        return null;
    }

    public override IDictionary<string, object> Serialize( 
            object obj, 
            JavaScriptSerializer serializer )
    {
        var dataObj = obj as DataObject;
        if( dataObj != null )
        {
            return new Dictionary<string,object>
            {
                {"user_id", dataObj.UserId },
                {"detail_level", dataObj.DetailLevel }
            }
        }
        return new Dictionary<string, object>();
    }
}

然后,您可以像这样反序列化:

代码语言:javascript
运行
复制
var serializer = new JavaScriptSerializer();
serialzer.RegisterConverters( new[]{ new DataObjectJavaScriptConverter() } );
var dataObj = serializer.Deserialize<DataObject>( json );
票数 20
EN

Stack Overflow用户

发布于 2009-07-11 02:24:41

Json.NET会做你想做的事情(免责声明:我是软件包的作者)。它支持读取DataContract/DataMember属性以及它自己的属性来更改属性名。还有一个StringEnumConverter类,用于将枚举值序列化为名称而不是数字。

票数 13
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/1100191

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档