反序列化期间的 JSON.Net Ignore Property
Posted
技术标签:
【中文标题】反序列化期间的 JSON.Net Ignore Property【英文标题】:JSON.Net Ignore Property during deserialization 【发布时间】:2012-10-05 21:44:24 【问题描述】:我的班级设置如下:
public class Foo
public string string1 get; set;
public string string2 get; set;
public string string3 get; set;
我正在使用 Json.Net 反序列化以下 Json 响应:
[
"number1": 1,
"number2": 12345678901234567890,
"number3": 3
,
"number1": 9,
"number2": 12345678901234567890,
"number3": 8
]
反序列化代码:
string json = @"[
""number1"": 1,
""number2"": 12345678901234567890,
""number3"": 3
,
""number1"": 9,
""number2"": 12345678901234567890,
""number3"": 8
]"
List<Foo> foos = JsonConvert.DeserializeObject<List<Foo>>(json);
number2
中的值超过了Int64
,但我并不真正关心检索该值。有没有办法将number2
属性转换为字符串,或者在反序列化过程中完全忽略它?
我尝试将[JsonConverter(typeof(string))]
属性添加到string2
属性,但收到错误:Error creating System.String
。我也试过设置typeof(decimal)
。
我也尝试过使用[JsonIgnore]
,但这不起作用。
【问题讨论】:
我通过使用 Regex.Replace() 删除条目解决了这个问题: string fixedResponse = Regex.Replace(json, "\\\"number2\\\": \\d+, " ,String.Empty); 你为什么不发布一个正确的答案? ***.com/questions/38054986/… 【参考方案1】:您可以使用JsonSerializerSettings
对象的MissingMemberHandling
属性。
示例用法:
var jsonSerializerSettings = new JsonSerializerSettings();
jsonSerializerSettings.MissingMemberHandling = MissingMemberHandling.Ignore;
JsonConvert.DeserializeObject<YourClass>(jsonResponse, jsonSerializerSettings);
更多信息here。
【讨论】:
他要求忽略特定密钥而不处理丢失的密钥,您的回答与问题无关 有趣的是,我们中有多少人实际上在寻找这个答案 - 即我们有一个不同的问题,但我们得到的答案是正确的。我几乎感觉超现实【参考方案2】:这是一个蹩脚的解决方法,但您可以创建一种手动加载 json 的方法。如果在没有自动反序列化器的情况下加载的数据太多,只需删除您不想要的节点。不过这要慢很多。
public static List<Foo> FromJson(string input)
var json = JToken.Parse(input);
json["key"].Remove();
var foo = JsonConvert.DeserializeObject<List<Foo>>(json.ToString());
这是一个有趣的问题,我想知道是否有人有更好的解决方案。
【讨论】:
此代码在 JToken.Parse(input) 处出错,它仍然无法解析 uInt64 :/ 这太糟糕了,看起来 Regex 是你现在最好的朋友。也许向 Json.net 人提交问题。【参考方案3】:这是 Newtonsoft Json 首选的方式来忽略一个属性,而不必修改基于 http://james.newtonking.com/json/help/index.html?topic=html/ReducingSerializedJSONSize.htm 的类
这个用来忽略EF或者Linq2Sql的惰性引用属性
public class DynamicContractResolver : DefaultContractResolver
protected override IList<JsonProperty> CreateProperties(Type type,
MemberSerialization memberSerialization)
Func<Type,bool> includeProperty = t => t.IsValueType || t.Namespace.StartsWith("System") && t.Namespace.StartsWith("System.Data")==false;
IList<JsonProperty> properties = base.CreateProperties(type, memberSerialization);
var allProperties = properties.Select (p => newp.PropertyName,Including=includeProperty(p.PropertyType), p.PropertyType);//.Dump("props");
var warnProperties=allProperties.Where (a =>a.Including && a.PropertyType.IsValueType==false && a.PropertyType.Name.IsIgnoreCaseMatch("String")==false) ;
//linq pad debugging helper
//var propertyTypesSerializing= allProperties.Where (p => p.Including).Select (p => p.PropertyType).Distinct().OrderBy (p => p.Name).Dump();
if(warnProperties.Any())
//LinqPad helper
//Util.Highlight(warnProperties.ToArray()).Dump("warning flag raised, aborting");
throw new ArgumentOutOfRangeException();
properties = properties.Where(p =>includeProperty(p.PropertyType)).ToList();
return properties;
所有.Dump()
调用只是linqpad 调试助手,不需要方法调用。
示例用法:
var inactives = from am in Aspnet_Memberships
join mm in Member_members on am.UserId equals mm.Member_guid
where mm.Is_active==false && mm.Org_id==1
select newam,mm;
//inactives.Take(4).ToArray().Dump();
var serialized = JsonConvert.SerializeObject(
inactives.Skip(1).Select(i => i.mm).First(),
new JsonSerializerSettings()
ContractResolver = new DynamicContractResolver(),
PreserveReferencesHandling = PreserveReferencesHandling.None,
ReferenceLoopHandling= ReferenceLoopHandling.Ignore
);
//.Dump();
【讨论】:
.IsIgnoreCaseMatch
?,这是否意味着.Equals("String", StringComparison.[xIgnoreCase])
?【参考方案4】:
类似于@Maslow's solution,可以使用another general purpose "ignorer":
var jsonResolver = new IgnorableSerializerContractResolver();
// ignore your specific property
jsonResolver.Ignore(typeof(Foo), "string2");
// ignore single datatype
jsonResolver.Ignore(typeof(System.Data.Objects.DataClasses.EntityObject));
var jsonSettings = new JsonSerializerSettings() ReferenceLoopHandling = ReferenceLoopHandling.Ignore, ContractResolver = jsonResolver ;
【讨论】:
那是序列化过程中的忽略,这个问题是关于反序列化的。 @Alrehamy 什么?引用问题>“......或在反序列化期间完全忽略它” 多年后基于@ohad-bitton's answer 我认为解析器不能双向工作。哦,好吧。 我遇到了同样的事情,但能够通过覆盖CreateProperties
方法来修复它:` protected override IList添加到 drzaus 答案:
您可以使用他建议的DefaultContractResolver
.. 只是在其CreateProperty
中使用property.Ignored = true;
而不是property.ShouldSerialize
,然后将JsonSerializerSettings
传递给DeserializeObject
函数或SerializeObject
函数时它都很好.
【讨论】:
对我不起作用;我还尝试了GetIsSpecified
,然后是tried to look at JsonConvert's source code,但我实际上并不认为这是可能的。也许用某种 noop 代替 property.ValueProvider
?
我测试了它并且它确实有效..你的情况发生了什么?
在我的情况下什么也没发生。它忽略了我对属性的忽视并继续反序列化。 ¯\_(ツ)_/¯
【参考方案6】:
另类;
如果 ResponseAttribute 有模型或字符串参数
public class ResponseAttribute : Attribute
public class ModelItem
[Response]
public Guid Id get; set;
代码;
public class CustomJsonSerializer : JsonSerializerSettings
public CustomJsonSerializer()
ContractResolver = new CustomContractResolver();
public CustomJsonSerializer(params string[] members)
ContractResolver = new CustomContractResolver(members);
public class CustomContractResolver : DefaultContractResolver
public string[] Members get; set;
public CustomContractResolver(params string[] _members)
Members = _members;
protected override JsonProperty CreateProperty(MemberInfo member, MemberSerialization memberSerialization)
JsonProperty property = base.CreateProperty(member, memberSerialization);
if (Members?.Length > 0)
property.ShouldSerialize = instance => return Members.Contains(member.Name); ;
else
property.ShouldSerialize = instance => return member.GetCustomAttribute<ResponseAttribute>() != null; ;
return property;
使用;
return new JsonResult(model, new CustomJsonSerializer());
或
return new JsonResult(model, new CustomJsonSerializer("Id","Test","Test2"));
【讨论】:
【参考方案7】:这段代码对我来说就像一个魅力:
using System.Reflection;
using Newtonsoft.Json;
using Newtonsoft.Json.Serialization;
public class PropertyRenameAndIgnoreSerializerContractResolver : DefaultContractResolver
private readonly Dictionary<Type, HashSet<string>> _ignores;
private readonly Dictionary<Type, Dictionary<string, string>> _renames;
public PropertyRenameAndIgnoreSerializerContractResolver()
_ignores = new Dictionary<Type, HashSet<string>>();
_renames = new Dictionary<Type, Dictionary<string, string>>();
public void IgnoreProperty(Type type, params string[] jsonPropertyNames)
if (!_ignores.ContainsKey(type))
_ignores[type] = new HashSet<string>();
foreach (var prop in jsonPropertyNames)
_ignores[type].Add(prop);
public void RenameProperty(Type type, string propertyName, string newJsonPropertyName)
if (!_renames.ContainsKey(type))
_renames[type] = new Dictionary<string, string>();
_renames[type][propertyName] = newJsonPropertyName;
protected override JsonProperty CreateProperty(MemberInfo member, MemberSerialization memberSerialization)
var property = base.CreateProperty(member, memberSerialization);
if (IsIgnored(property.DeclaringType, property.PropertyName))
property.ShouldSerialize = i => false;
property.Ignored = true;
if (IsRenamed(property.DeclaringType, property.PropertyName, out var newJsonPropertyName))
property.PropertyName = newJsonPropertyName;
return property;
private bool IsIgnored(Type type, string jsonPropertyName)
if (!_ignores.ContainsKey(type))
return false;
return _ignores[type].Contains(jsonPropertyName);
private bool IsRenamed(Type type, string jsonPropertyName, out string newJsonPropertyName)
Dictionary<string, string> renames;
if (!_renames.TryGetValue(type, out renames) || !renames.TryGetValue(jsonPropertyName, out newJsonPropertyName))
newJsonPropertyName = null;
return false;
return true;
//忽略 Foo 示例中的 number2
public class Foo
public string number1 get; set;
public string number2 get; set;
public string number3 get; set;
string Foojson = @"[
""number1"": 1,
""number2"": 12345678901234567890,
""number3"": 3
,
""number1"": 9,
""number2"": 12345678901234567890,
""number3"": 8
]";
var jsonResolverFoo = new PropertyRenameAndIgnoreSerializerContractResolver();
jsonResolverFoo.IgnoreProperty(typeof(Foo), "number2");
var serializerSettingsFoo = new JsonSerializerSettings();
serializerSettingsFoo.ContractResolver = jsonResolverFoo;
var deserializedJsonFoo = JsonConvert.DeserializeObject<List<Foo>>(Foojson, serializerSettingsFoo);
/* 资源链接:https://blog.rsuter.com/advanced-newtonsoft-json-dynamically-rename-or-ignore-properties-without-changing-the-serialized-class/ */
【讨论】:
【参考方案8】:我遇到了类似的情况,但我的类包含 List 和 Dictionary 已填充且不应被 JSON 文件所包含的任何内容覆盖。与当时我能找到的任何其他方法相比,我更容易将数据加载到临时对象中,然后只需拉出我需要的项目。
所以对于这个例子,类似这样的东西......
public class Foo
public string string1 get; set;
public string string2 get; set;
public string string3 get; set;
List<Foo> foos = new List<Foo>();
List<Foo> tmp= JsonConvert.DeserializeObject<List<Foo>>(json);
foreach(Foo item in tmp)
foos.string1 = tmp.string1;
foos.string3 = tmp.string3;
【讨论】:
以上是关于反序列化期间的 JSON.Net Ignore Property的主要内容,如果未能解决你的问题,请参考以下文章
Json.NET 反序列化或序列化 json 字符串并将属性映射到运行时定义的不同属性名称