是否可以确定在 Json.Net 中反序列化了哪些属性? [复制]
Posted
技术标签:
【中文标题】是否可以确定在 Json.Net 中反序列化了哪些属性? [复制]【英文标题】:Is it possible to determine which properties were deserialised in Json.Net? [duplicate] 【发布时间】:2021-01-27 17:12:12 【问题描述】:假设我有以下 JSON:
"name": "Jim",
"age": 20
我将其反序列化为以下 C# 对象:
public class Person
[JsonProperty("name")]
public string Name get; set;
[JsonProperty("age")]
public int? Age get; set;
[JsonProperty("height")]
public int? Height get; set;
有什么方法可以确定原始 JSON 中包含哪些属性,哪些属性被省略了?
在这个例子中,我的所有属性都可以为空,JSON 不包含 height
属性,所以我的 C# 对象最终会得到一个 null
Height
。
但是,用户也可以简单地提供null
作为高度,例如
"name": "Jim",
"age": 20,
"height": null
所以我的问题是:我是否可以确定是否提供了值但null
,或者未提供值因此默认为null
。是否有一些可用的元数据在某处/以某种方式为我提供了这些信息?
这是在 ApiController 中使用的,因此反序列化是由 Formatter 自动完成的,但这是我当前的 formatter 设置:
private static void AddFormatter(HttpConfiguration config)
var formatter = config.Formatters.JsonFormatter;
formatter.SerializerSettings = new JsonSerializerSettings
Formatting = Formatting.Indented,
TypeNameHandling = TypeNameHandling.None
;
【问题讨论】:
在业务逻辑方面,不提供高度和提供为空的高度有什么区别? 这是我用来更新一些其他数据的示例中间对象。最好我只想在初始 JSON 中提供的最终对象上设置字段。 How to configure JSON.net deserializer to track missing properties? 看起来是重复的。同意吗? @dbc 同意,感谢您的发现! 【参考方案1】:您可以使用DefaultValueHandling
属性定义处理可空值的策略,如[JsonProperty(DefaultValueHandling = DefaultValueHandling.Ignore)]
,您可以阅读更多选项here.
尝试添加用户无法提供的默认值,然后您就会知道该值是否是用户提供的。
public class Person
[JsonProperty("name")]
public string Name get; set;
[JsonProperty("age")]
public int? Age get; set;
[DefaultValue(-1)]
[JsonProperty("height", DefaultValueHandling = DefaultValueHandling.Populate)]
public int? Height get; set;
【讨论】:
不确定这如何帮助我实现目标...? 尝试添加默认值,更新我的答案【参考方案2】:由于缺乏响应,除非svyatis.lviv 提供有用但不是很好的建议,我决定以一种简单的非序列化相关方式实现它。
首先我做了这个界面:
public interface IPropertyChangeLog
IEnumerable<string> PropertiesChanged get;
void Reset();
然后我制作了这个助手类:
public class PropertyChangeLog<TSource> : IPropertyChangeLog
where TSource : IPropertyChangeLog
private readonly List<string> _changes = new List<string>();
public void UpdateProperty<TValue>(TValue newValue, ref TValue oldValue, [CallerMemberName] string propertyName = null)
oldValue = newValue;
_changes.Add(propertyName);
public IEnumerable<string> PropertiesChanged => _changes;
public void Reset() => _changes.Clear();
最后,我更新了Person
类如下:
public class Person : IPropertyChangeLog
private PropertyChangeLog<Person> _log = new PropertyChangeLog<Person>();
private string _name;
private int? _age;
private int? _height;
[JsonProperty("name")]
public string Name
get => _name;
set => _log.UpdateProperty(value, ref _name);
[JsonProperty("age")]
public int? Age
get => _age;
set => _log.UpdateProperty(value, ref _age);
[JsonProperty("height")]
public int? Height
get => _height;
set => _log.UpdateProperty(value, ref _height);
IEnumerable<string> IPropertyChangeLog.PropertiesChanged => _log.PropertiesChanged;
void IPropertyChangeLog.Reset() => _log.Reset();
它比我想要的要冗长一些,但它仍然非常简单易读。
为了使用它:
var person = JsonConvert.DeserializeObject<Person>(" \"name\": \"test\" ");
var log = (IPropertyChangeLog)person;
// log.PropertiesChanged should now contain 'Name'
foreach (var property in log.PropertiesChanged)
// we know that the property named in 'property' changed
log.Reset();
JsonConvert.PopulateObject(" \"age\": null ", person);
// now log.PropertiesChanged should only contain 'Age'
foreach (var property in log.PropertiesChanged)
// we know that the property named in 'property' changed
【讨论】:
以上是关于是否可以确定在 Json.Net 中反序列化了哪些属性? [复制]的主要内容,如果未能解决你的问题,请参考以下文章