Ant*_*ony 72 c# serialization parsing json javascriptserializer
简介:在使用JavaScriptSerializer.Deserialize时,如何将JSON数据中的字段名称映射到.Net对象的字段名称?
更长版本:我从服务器API(未在.Net中编码)向我发送以下JSON数据
{"user_id":1234, "detail_level":"low"}
Run Code Online (Sandbox Code Playgroud)
我有以下C#对象:
[Serializable]
public class DataObject
{
[XmlElement("user_id")]
public int UserId { get; set; }
[XmlElement("detail_level")]
public DetailLevel DetailLevel { get; set; }
}
Run Code Online (Sandbox Code Playgroud)
其中DetailLevel是一个枚举,其中"低"作为其中一个值.
此测试失败:
[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);
}
Run Code Online (Sandbox Code Playgroud)
最后两个断言失败,因为这些字段中没有数据.如果我将JSON数据更改为
{"userid":1234, "detaillevel":"low"}
Run Code Online (Sandbox Code Playgroud)
然后它通过.但我不能改变服务器的行为,我希望客户端类在C#语言中具有良好命名的属性.我不能使用LINQ to JSON,因为我希望它在Silverlight之外工作.看起来XmlElement标签没有任何效果.我不知道我在哪里知道它们是相关的,它们可能不是.
你如何在JavaScriptSerializer中进行字段名称映射?它可以完成吗?
Ant*_*ony 72
我使用DataContractJsonSerializer类再次尝试它.这解决了它:
代码如下所示:
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; }
}
Run Code Online (Sandbox Code Playgroud)
测试是:
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);
}
Run Code Online (Sandbox Code Playgroud)
唯一的缺点是我必须将DetailLevel从枚举更改为字符串 - 如果保持枚举类型,DataContractJsonSerializer期望读取数值并失败.有关更多详细信息,请参阅DataContractJsonSerializer和Enums.
在我看来,这是非常差的,特别是当JavaScriptSerializer正确处理它时.这是您尝试将字符串解析为枚举的例外:
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
Run Code Online (Sandbox Code Playgroud)
并且像这样标记枚举不会改变这种行为:
[DataContract]
public enum DetailLevel
{
[EnumMember(Value = "low")]
Low,
...
}
Run Code Online (Sandbox Code Playgroud)
这似乎也适用于Silverlight.
Pau*_*der 20
通过创建自定义JavaScriptConverter,您可以将任何名称映射到任何属性.但它确实需要手工编码地图,这不太理想.
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>();
}
}
Run Code Online (Sandbox Code Playgroud)
然后你可以这样反序列化:
var serializer = new JavaScriptSerializer();
serialzer.RegisterConverters( new[]{ new DataObjectJavaScriptConverter() } );
var dataObj = serializer.Deserialize<DataObject>( json );
Run Code Online (Sandbox Code Playgroud)
Tom*_*her 11
对于重命名属性没有标准支持,JavaScriptSerializer但是您可以非常轻松地添加自己的属性:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Web.Script.Serialization;
using System.Reflection;
public class JsonConverter : JavaScriptConverter
{
public override object Deserialize(IDictionary<string, object> dictionary, Type type, JavaScriptSerializer serializer)
{
List<MemberInfo> members = new List<MemberInfo>();
members.AddRange(type.GetFields());
members.AddRange(type.GetProperties().Where(p => p.CanRead && p.CanWrite && p.GetIndexParameters().Length == 0));
object obj = Activator.CreateInstance(type);
foreach (MemberInfo member in members)
{
JsonPropertyAttribute jsonProperty = (JsonPropertyAttribute)Attribute.GetCustomAttribute(member, typeof(JsonPropertyAttribute));
if (jsonProperty != null && dictionary.ContainsKey(jsonProperty.Name))
{
SetMemberValue(serializer, member, obj, dictionary[jsonProperty.Name]);
}
else if (dictionary.ContainsKey(member.Name))
{
SetMemberValue(serializer, member, obj, dictionary[member.Name]);
}
else
{
KeyValuePair<string, object> kvp = dictionary.FirstOrDefault(x => string.Equals(x.Key, member.Name, StringComparison.InvariantCultureIgnoreCase));
if (!kvp.Equals(default(KeyValuePair<string, object>)))
{
SetMemberValue(serializer, member, obj, kvp.Value);
}
}
}
return obj;
}
private void SetMemberValue(JavaScriptSerializer serializer, MemberInfo member, object obj, object value)
{
if (member is PropertyInfo)
{
PropertyInfo property = (PropertyInfo)member;
property.SetValue(obj, serializer.ConvertToType(value, property.PropertyType), null);
}
else if (member is FieldInfo)
{
FieldInfo field = (FieldInfo)member;
field.SetValue(obj, serializer.ConvertToType(value, field.FieldType));
}
}
public override IDictionary<string, object> Serialize(object obj, JavaScriptSerializer serializer)
{
Type type = obj.GetType();
List<MemberInfo> members = new List<MemberInfo>();
members.AddRange(type.GetFields());
members.AddRange(type.GetProperties().Where(p => p.CanRead && p.CanWrite && p.GetIndexParameters().Length == 0));
Dictionary<string, object> values = new Dictionary<string, object>();
foreach (MemberInfo member in members)
{
JsonPropertyAttribute jsonProperty = (JsonPropertyAttribute)Attribute.GetCustomAttribute(member, typeof(JsonPropertyAttribute));
if (jsonProperty != null)
{
values[jsonProperty.Name] = GetMemberValue(member, obj);
}
else
{
values[member.Name] = GetMemberValue(member, obj);
}
}
return values;
}
private object GetMemberValue(MemberInfo member, object obj)
{
if (member is PropertyInfo)
{
PropertyInfo property = (PropertyInfo)member;
return property.GetValue(obj, null);
}
else if (member is FieldInfo)
{
FieldInfo field = (FieldInfo)member;
return field.GetValue(obj);
}
return null;
}
public override IEnumerable<Type> SupportedTypes
{
get
{
return new[] { typeof(DataObject) };
}
}
}
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
[AttributeUsage(AttributeTargets.Field | AttributeTargets.Property)]
public class JsonPropertyAttribute : Attribute
{
public JsonPropertyAttribute(string name)
{
Name = name;
}
public string Name
{
get;
set;
}
}
Run Code Online (Sandbox Code Playgroud)
DataObject然后该课程成为:
public class DataObject
{
[JsonProperty("user_id")]
public int UserId { get; set; }
[JsonProperty("detail_level")]
public DetailLevel DetailLevel { get; set; }
}
Run Code Online (Sandbox Code Playgroud)
我认为这可能有点晚,但认为其他人想要使用JavaScriptSerializer而不是DataContractJsonSerializer可能会欣赏它.
创建一个继承自JavaScriptConverter的类.然后你必须实现三件事:
方法-
属性-
当您需要对序列化和反序列化过程进行更多控制时,可以使用JavaScriptConverter类.
JavaScriptSerializer serializer = new JavaScriptSerializer();
serializer.RegisterConverters(new JavaScriptConverter[] { new MyCustomConverter() });
DataObject dataObject = serializer.Deserialize<DataObject>(JsonData);
Run Code Online (Sandbox Code Playgroud)
小智 5
我使用了下面的 Newtonsoft.Json。创建一个对象:
public class WorklistSortColumn
{
[JsonProperty(PropertyName = "field")]
public string Field { get; set; }
[JsonProperty(PropertyName = "dir")]
public string Direction { get; set; }
[JsonIgnore]
public string SortOrder { get; set; }
}
Run Code Online (Sandbox Code Playgroud)
现在调用下面的方法序列化为 Json 对象,如下所示。
string sortColumn = JsonConvert.SerializeObject(worklistSortColumn);
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
99682 次 |
| 最近记录: |