栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 面试经验 > 面试问答

Json.NET序列化中是否有一种方法可以区分“因为不存在而为空”和“因为没有而为空”?

面试问答 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

Json.NET序列化中是否有一种方法可以区分“因为不存在而为空”和“因为没有而为空”?

如果使用Json.Net的LINQ-to-JSON
API
(JTokens,JObjects等)来解析JSON,则可以分辨出JSON

null
中根本不存在的值和字段之间的区别。例如:

JToken root = JToken.Parse(json);JToken nested = root["nested"];if (nested != null){    if (nested.Type == JTokenType.Null)    {        Console.WriteLine("nested is set to null");    }    else    {        Console.WriteLine("nested has a value: " + nested.ToString());    }}else{    Console.WriteLine("nested does not exist");}

小提琴:https://dotnetfiddle.net/VJO7ay

更新

如果要使用Web
API反序列化为具体对象,则仍可以通过创建自定义

JsonConverter
来处理DTO来使用上述概念。问题是在反序列化期间,您的DTO上需要有一个位置来存储字段状态。我建议使用像这样的基于字典的方案:

enum FieldDeserializationStatus { WasNotPresent, WasSetToNull, HasValue }interface IHasFieldStatus{    Dictionary<string, FieldDeserializationStatus> FieldStatus { get; set; }}class FooDTO : IHasFieldStatus{    public string Field1 { get; set; }    public BarDTO Nested { get; set; }    public Dictionary<string, FieldDeserializationStatus> FieldStatus { get; set; }}class BarDTO : IHasFieldStatus{    public int Num { get; set; }    public string Str { get; set; }    public bool Bool { get; set; }    public decimal Dec { get; set; }    public Dictionary<string, FieldDeserializationStatus> FieldStatus { get; set; }}

然后,自定义转换器将使用上述LINQ-to-
JSON技术来读取要反序列化的对象的JSON。对于目标对象中的每个字段,它将在该对象的

FieldStatus
字典中添加一个项目,指示该字段是否具有值,是否已显式设置为null或在JSON中不存在。代码如下所示:

class DtoConverter : JsonConverter{    public override bool CanConvert(Type objectType)    {        return (objectType.IsClass &&      objectType.GetInterfaces().Any(i => i == typeof(IHasFieldStatus)));    }    public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)    {        var jsonObj = JObject.Load(reader);        var targetObj = (IHasFieldStatus)Activator.CreateInstance(objectType);        var dict = new Dictionary<string, FieldDeserializationStatus>();        targetObj.FieldStatus = dict;        foreach (PropertyInfo prop in objectType.GetProperties())        { if (prop.CanWrite && prop.Name != "FieldStatus") {     JToken value;     if (jsonObj.TryGetValue(prop.Name, StringComparison.OrdinalIgnoreCase, out value))     {         if (value.Type == JTokenType.Null)         {  dict.Add(prop.Name, FieldDeserializationStatus.WasSetToNull);         }         else         {  prop.SetValue(targetObj, value.ToObject(prop.PropertyType, serializer));  dict.Add(prop.Name, FieldDeserializationStatus.HasValue);         }     }     else     {         dict.Add(prop.Name, FieldDeserializationStatus.WasNotPresent);     } }        }        return targetObj;    }    public override bool CanWrite    {        get { return false; }    }    public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)    {        throw new NotImplementedException();    }}

上面的转换器将在实现该

IHasFieldStatus
接口的任何对象上工作。(请注意,
WriteJson
除非您也打算对序列化做一些自定义操作,否则不需要在转换器中实现该方法。由于
CanWrite
返回false,因此在序列化期间将不使用转换器。)

现在,要在Web API中使用转换器,您需要将其插入配置中。将此添加到您的

Application_Start()
方法:

var config = GlobalConfiguration.Configuration;var jsonSettings = config.Formatters.JsonFormatter.SerializerSettings;jsonSettings.C‌​onverters.Add(new DtoConverter());

如果愿意,可以用这样的

[JsonConverter]
属性装饰每个DTO,而不用在全局配置中设置转换器:

[JsonConverter(typeof(DtoConverter))]class FooDTO : IHasFieldStatus{    ...}

有了转换器基础结构之后,您可以

FieldStatus
在反序列化之后在DTO上查询字典,以查看任何特定字段发生了什么。这是完整的演示(控制台应用程序):

public class Program{    public static void Main()    {        ParseAndDump("First run", @"{ ""field1"": ""my field 1"", ""nested"": {     ""num"": null,     ""str"": ""blah"",     ""dec"": 3.14 }        }");        ParseAndDump("Second run", @"{ ""field1"": ""new field value""        }");        ParseAndDump("Third run", @"{ ""nested"": null        }");    }    private static void ParseAndDump(string comment, string json)    {        Console.WriteLine("--- " + comment + " ---");        JsonSerializerSettings settings = new JsonSerializerSettings();        settings.Converters.Add(new DtoConverter());        FooDTO foo = JsonConvert.DeserializeObject<FooDTO>(json, settings);        Dump(foo, "");        Console.WriteLine();    }    private static void Dump(IHasFieldStatus dto, string indent)    {        foreach (PropertyInfo prop in dto.GetType().GetProperties())        { if (prop.Name == "FieldStatus") continue; Console.Write(indent + prop.Name + ": "); object val = prop.GetValue(dto); if (val is IHasFieldStatus) {     Console.WriteLine();     Dump((IHasFieldStatus)val, "  "); } else {     FieldDeserializationStatus status = dto.FieldStatus[prop.Name];     if (val != null)          Console.Write(val.ToString() + " ");     if (status != FieldDeserializationStatus.HasValue)         Console.Write("(" + status + ")");     Console.WriteLine(); }        }    }   }

输出:

--- First run ---Field1: my field 1 Nested:   Num: 0 (WasSetToNull)  Str: blah   Bool: False (WasNotPresent)  Dec: 3.14--- Second run ---Field1: new field value Nested: (WasNotPresent)--- Third run ---Field1: (WasNotPresent)Nested: (WasSetToNull)

小提琴:https :
//dotnetfiddle.net/xyKrg2



转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/507036.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号