Подтвердить что ты не робот

JSON.Net: принудительная сериализация всех частных полей и всех полей в подклассах

У меня есть класс с несколькими разными классами, и я отправляю информацию в этих классах клиентам, но я не хочу отправлять их всем, поэтому некоторые из них являются частными, некоторые имеют флаг [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);
4b9b3361

Ответ 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;
    }
}

Ответ 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;
    }
}

... кажется, работает.

Ответ 3

Удивительное спасибо @L.B. Здесь полная реализация в .linq script в случае, если кто-то хочет протестировать с частными подклассами - например. См. 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
  }
}