using System.IO;
using System.Runtime.Serialization;
using System.Runtime.Serialization.Json;
using System.Text;
namespace ConsoleApplication1 {
internal class Program {
private static void Main(string[] args) {
var pony = new Pony();
var serializer = new DataContractJsonSerializer(pony.GetType());
var example = @"{""Foo"":null}";
var stream = new MemoryStream(Encoding.UTF8.GetBytes(example.ToCharArray()));
stream.Position = 0;
pony = (Pony) serializer.ReadObject(stream);
// The previous line throws an exception.
}
}
[DataContract]
public class Pony {
[DataMember]
private int Foo { get; set; }
}
}
有时,序列化会将Int32s上的转换错误设置为null。 有没有办法挂钩Json-serializer?
答案 0 :(得分:2)
恕我直言,最好的办法是将Foo
类型从Int32
更改为System.Nullable<Int32>
,因为这样可以最好地反映其语义(如果它可以为null)但是如果你不能修改它class AND如果使用DataContractJsonSerializer不是您的义务,Json.NET具有允许您执行此操作的扩展点(它也恰好是better performing)。
例如,您可以编写自定义类型转换器:
internal class NullableIntConverter : JsonConverter
{
public override bool CanConvert(Type objectType)
{
return objectType == typeof(int);
}
public override object ReadJson(JsonReader reader, Type objectType, JsonSerializer serializer)
{
if (reader.Value == null)
{
return default(int);
}
return int.Parse(reader.Value.ToString());
}
public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
{
throw new System.NotImplementedException();
}
}
可以像这样注册和使用:
internal class Program
{
private static void Main(string[] args)
{
var serializer = new JsonSerializer();
serializer.Converters.Add(new NullableIntConverter());
using (var reader = new StringReader(@"{""Foo"":null}"))
using (var jsonReader = new JsonTextReader(reader))
{
var pony = serializer.Deserialize<Pony>(jsonReader);
Console.WriteLine(pony.Foo);
}
}
}
答案 1 :(得分:1)
使其工作的最简单方法是将int设置为可为空的int。我通过示例代码进行了调试,看起来效果很好。
[DataContract]
public class Pony
{
[DataMember]
private int? Foo { get; set; }
}
答案 2 :(得分:1)
如果您使用的是.NET 3.5或更高版本(我希望您这样做),则可以使用JavaScriptSerializer代替。它更“动态”(不需要[DataContract]和[DataMember]属性),我之前从未遇到任何问题。 你只需拿起你想要的任何对象,任何类型并用它序列化:)
在.net 3.5中,它是System.Web.Extensions.dll的一部分,但在.NET 4中,此程序集现在是框架的一部分。
您可以轻松地将自己的自定义串行器代码添加到其中,并手动处理。通过这种方式,您可以获得所需的控件,并且您将知道哪些属性行为不当!
e.g:
void Main()
{
var js = new JavaScriptSerializer();
js.RegisterConverters(new[] { new PonySerializer() });
var pony = js.Deserialize<Pony>(@"{""Foo"":""null""}");
pony.Dump();
}
public class PonySerializer : JavaScriptConverter
{
public override IEnumerable<Type> SupportedTypes
{
get { return new [] { typeof(Pony) }; }
}
public override IDictionary<string, object> Serialize(object obj, JavaScriptSerializer serializer)
{
throw new NotImplementedException();
}
public override object Deserialize(IDictionary<string, object> dictionary, Type type, JavaScriptSerializer serializer)
{
if (dictionary == null)
throw new ArgumentNullException("dictionary");
if (type == typeof(Pony))
{
var pony = new Pony();
int intValue;
if (!int.TryParse(dictionary["Foo"] as string, out intValue))
intValue = -1; // default value. You can throw an exception or log it or do whatever you want here
pony.Foo = intValue;
return pony;
}
return null;
}
}
public class Pony
{
public int Foo { get; set; }
}
P.S。这个例子是用LinqPad编写的,因此缺少使用,Main()等参数:P
答案 3 :(得分:0)
DataContractJsonSerializer
具有您可以分配的DataContractSurrogate属性。您的代理类(IDataContractSurrogate
的实现)可以在其GetDeserializedObject中自定义处理空值。