【问题标题】:JSON.Net: Force serialization of all private fields and all fields in sub-classesJSON.Net:强制序列化所有私有字段和子类中的所有字段
【发布时间】:2014-07-29 05:00:36
【问题描述】:

我有一个包含几个不同类的类,我将这些类中的信息发送给客户,但我不想将它们全部发送出去,所以有些是私有的,有些有 [JsonObject(MemberSerialization.OptIn)] 标志等。

但是,现在我想在需要关闭服务器时以及每 12 小时(我不想使用数据库)对所有这些对象进行备份,所以我想要做的(如果可能的话)是强制 JSON.Net Serializer 转换对象和属于该对象的所有对象。

例如:

class Foo
{
  public int Number;
  private string name;
  private PrivateObject po = new PrivateObject();

  public string ToJSON()
  { /* Serialize my public field, my property and the object PrivateObject */ }
}

我尝试了这段代码(即使它已经过时),但它没有序列化与我的对象相关的对象:

Newtonsoft.Json.JsonSerializerSettings jss = new Newtonsoft.Json.JsonSerializerSettings();

Newtonsoft.Json.Serialization.DefaultContractResolver dcr = new Newtonsoft.Json.Serialization.DefaultContractResolver();
dcr.DefaultMembersSearchFlags |= System.Reflection.BindingFlags.NonPublic;
jss.ContractResolver = dcr;

return Newtonsoft.Json.JsonConvert.SerializeObject(this, jss);

【问题讨论】:

    标签: c# json.net


    【解决方案1】:

    这应该可行:

    var settings = new JsonSerializerSettings() { ContractResolver = new MyContractResolver() };
    var json = JsonConvert.SerializeObject(obj, settings);
    

    public class MyContractResolver : Newtonsoft.Json.Serialization.DefaultContractResolver
    {
        protected override IList<JsonProperty> CreateProperties(Type type, MemberSerialization memberSerialization)
        {
            var props = type.GetProperties(BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance)
                            .Select(p => base.CreateProperty(p, memberSerialization))
                        .Union(type.GetFields(BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance)
                                   .Select(f => base.CreateProperty(f, memberSerialization)))
                        .ToList();
            props.ForEach(p => { p.Writable = true; p.Readable = true; });
            return props;
        }
    }
    

    【讨论】:

    • 是否可以包含没有 [JsonProperty] 的属性和它的类 [JsonObject(MemberSerialization.OptIn)]?
    • @user2524586 当然,JsonPropertyJsonObject 不是必须。它们只是 JsonConvert 的提示
    • 我写得不好。我的意思是,即使在类上设置了 [JsonObject(MemberSerialization.OptIn)] ,我也可以在 ContractResolver 中包含没有设置 JsonProperty 属性的属性,以便我将获得所有字段和属性(尽管有 5 个10 是否设置了 JsonProperty 属性)?
    • 您可能需要检查类型参数(取决于您正在序列化的对象的复杂性)。当 JSON.NET 尝试查找错误类型的某些字段时,我遇到了异常。
    • 这个方法太慢了
    【解决方案2】:

    @L.B 的回答很棒。但是...它需要 .NET 3.5 或更高版本。

    对于我们这些坚持 2.0 的人...

    public class ForceJSONSerializePrivatesResolver : Newtonsoft.Json.Serialization.DefaultContractResolver
    {
        protected override IList<Newtonsoft.Json.Serialization.JsonProperty> CreateProperties(System.Type type, MemberSerialization memberSerialization)
        {
            var props = type.GetProperties(System.Reflection.BindingFlags.Public | System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Instance);
    
            List<Newtonsoft.Json.Serialization.JsonProperty> jsonProps = new List<Newtonsoft.Json.Serialization.JsonProperty>();
    
            foreach( var prop in props )
            {
            jsonProps.Add( base.CreateProperty(prop, memberSerialization));
            }
    
            foreach( var field in type.GetFields(System.Reflection.BindingFlags.Public | System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Instance) )
            {
            jsonProps.Add ( base.CreateProperty( field, memberSerialization ) );
            }
    
            jsonProps.ForEach(p => { p.Writable = true; p.Readable = true; });
            return jsonProps;
        }
    }
    

    ...似乎有效。

    【讨论】:

    • 我不记得了。 .Net 2.0 是否支持 lamba expr ( jsonProps.ForEach(p =&gt; { p.Writable = true; p.Readable = true; }); ),ForEach 是否在 2.0 中可用?
    • 它似乎。 msdn.microsoft.com/en-us/library/bwabdf9z(v=vs.80).aspx + 与 MSDN 文档中的 lambda 同上——但我在 Unity3d 中使用/测试 2.0,它有时会从 3.5 中获取位,所以我可能在这里弄错了。
    • @L.B 发布新答案时,该问题会在 StackOverflow 的“问题”部分中占据首页,就像新问题一样...
    【解决方案3】:

    非常感谢@L.B.这是 .linq 脚本中的完整实现,以防有人想使用私有子类进行测试 - 例如请参阅 A 具有私有子类 B。

    void Main()
    {
        var a = A.Test();
        SerialiseAllFields.Dump(a);
    }
    
    class A
    {
        private int PrivField1;
        private int PrivProp1 { get; set; }
        private B PrivSubClassField1;
    
        public static A Test()
        {
            return new A { PrivField1 = 1, PrivProp1 = 2, PrivSubClassField1 = B.Test() };
        }
    }
    
    class B
    {
        private int PrivField1;
        private int PrivProp1 { get; set; }
    
        public static B Test()
        {
            return new B { PrivField1 = 3, PrivProp1 = 4 };
        }
    }
    
    // Define other methods and classes here
    public static class SerialiseAllFields
    {
        public static void Dump(object o, bool indented = true)
        {
            var settings = new Newtonsoft.Json.JsonSerializerSettings() { ContractResolver = new AllFieldsContractResolver() };
            if (indented)
            {
                settings.Formatting = Newtonsoft.Json.Formatting.Indented;
            }
            Newtonsoft.Json.JsonConvert.SerializeObject(o, settings).Dump();
        }
    }
    
    public class AllFieldsContractResolver : Newtonsoft.Json.Serialization.DefaultContractResolver
    {
        protected override IList<Newtonsoft.Json.Serialization.JsonProperty> CreateProperties(Type type, Newtonsoft.Json.MemberSerialization memberSerialization)
        {
            var props = type
                .GetProperties(BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance)
                .Select(p => base.CreateProperty(p, memberSerialization))
                .Union(type.GetFields(BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance)
                .Select(f => base.CreateProperty(f, memberSerialization)))
                .ToList();
            props.ForEach(p => { p.Writable = true; p.Readable = true; });
            return props;
        }
    }
    

    有趣的是属性的支持字段也是序列化的,即输出是:

    {
      "PrivProp1": 2,
      "PrivField1": 1,
      "<PrivProp1>k__BackingField": 2,
      "PrivSubClassField1": {
        "PrivProp1": 4,
        "PrivField1": 3,
        "<PrivProp1>k__BackingField": 4
      }
    }
    

    【讨论】:

    • 您可以在ToList() 语句之前添加.Where(p=&gt;!p.PropertyName.Contains("k__BackingField")) 以消除支持字段。
    • 有一个内置的解决方案:“if ( field.IsDefined( typeof( CompilerGeneratedAttribute ), false ) == true )”
    【解决方案4】:

    这是以前接受的答案的修改版本,这也是serialize private fields/properties。性能有点提高。 (没有 BinaryFormatter 的序列化会慢一点)

    public class CloneContractResolver : Newtonsoft.Json.Serialization.DefaultContractResolver
    {
        protected override IList<JsonProperty> CreateProperties(Type type,
                                    MemberSerialization memberSerialization)
        {
            List<MemberInfo> members = GetSerializableMembers(type);
            if (members == null)
             throw new JsonSerializationException("Null collection of serializable members returned.");
    
            members.AddRange(type.GetProperties(BindingFlags.NonPublic | BindingFlags.Instance)
                .Where(f => !f.CustomAttributes.Any(x => x.AttributeType
                    == typeof(System.Runtime.CompilerServices.CompilerGeneratedAttribute))));
    
            members.AddRange(type.GetFields(BindingFlags.NonPublic | BindingFlags.Instance)
                .Where(f => !f.CustomAttributes.Any(x => x.AttributeType
                    == typeof(System.Runtime.CompilerServices.CompilerGeneratedAttribute))));
    
            JsonPropertyCollection properties = new JsonPropertyCollection(type);
            members.ForEach(member =>
            {
                JsonProperty property = CreateProperty(member, memberSerialization);
                property.Writable = true;
                property.Readable = true;
                properties.AddProperty(property);
            });
            return properties;
        }
    }
    

    在我看来,这种方法会占用更多内存

    public static class CloneHelper
    {
        private readonly static JsonSerializerSettings clone_settings = new JsonSerializerSettings() { ContractResolver = new CloneContractResolver() };
        public static T Clone<T>(this object source)
        {
            T entity = JsonConvert.DeserializeObject<T>(JsonConvert.SerializeObject(source, clone_settings), clone_settings);
            return entity;
        }
    }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2015-11-07
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2019-04-26
      • 2016-01-14
      • 2015-10-09
      • 1970-01-01
      相关资源
      最近更新 更多