【问题标题】:JSON.Net Ignore Property during deserialization反序列化期间的 JSON.Net Ignore Property
【发布时间】: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);
  • 你为什么不发布一个正确的答案?

标签: c# json json.net


【解决方案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 => new{p.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 new{am,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 CreateProperties(Type type, MemberSerialization memberSerialization) { var properties = base. CreateProperties(type, memberSerialization); foreach (var p in Ignores.SelectMany((type) => type.Value)) { properties.Add(new JsonProperty() { PropertyName = p }); } 返回属性; }`
【解决方案5】:

添加到 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;
      }
      

      【讨论】:

        猜你喜欢
        • 2015-01-26
        • 1970-01-01
        • 2012-04-09
        • 1970-01-01
        • 2015-09-25
        • 1970-01-01
        • 1970-01-01
        • 2012-12-18
        相关资源
        最近更新 更多