Why are some members missing when trying to print an object by serializing in JSON?

How to print any arbitrary variable in C # to print all elements?

I found three answers with the same technique:

However, when I tried this, with the following code,

using System; using System.Collections.Generic; using Newtonsoft.Json; public static class Program { public static void Main() { Test t1 = new Test(1, 2); { string json = JsonConvert.SerializeObject(t1, Formatting.Indented); Console.WriteLine(json); } Dump(t1); // Add 3 objects to a List. List<Test> list = new List<Test>(); list.Add(new Test(1, 2)); list.Add(new Test(3, 4)); list.Add(new Test(5, 6)); Console.WriteLine(list.ToString()); { string json = JsonConvert.SerializeObject(list, Formatting.Indented); Console.WriteLine(json); } } public class Test { int A; int b; public Test(int _a, int _b) { A = _a; b = _b; } }; public static void Dump<T>(this T x) { string json = JsonConvert.SerializeObject(x, Formatting.Indented); Console.WriteLine(json); } } 

All I have is empty Test outputs:

 {} {} System.Collections.Generic.List`1[Program+Test] [ {}, {}, {} ] 

Why are all my class members missing when serializing in JSON with Json.NET?

+1
source share
1 answer

By default, Json.NET only serializes public properties and fields. Your fields A and b are private . In order for Json.NET to serialize non-public (private or internal) members, you can:

  1. Make them public:

     public int A; public int b; 

    However, stylistically, if you are going to make them public, it is better to convert them into properties:

     public class Test { public int A { get; private set; } public int b { get; private set; } public Test(int a, int b) { this.A = a; this.b = b; } }; 

    To gain access to Json.NET, only public access is required.

  2. Check then with [JsonProperty] :

     [JsonProperty] int A; [JsonProperty] int b; 

    This also works for non-public property.

  3. Tag your object with [DataContract] , and your fields with [DataMember] :

     [DataContract] public class Test { [DataMember] int A; [DataMember] int b; public Test(int _a, int _b) { A = _a; b = _b; } }; 

    Please note that serialization of the data contract is mandatory, so you need to mark each member for serialization using [DataMember] . This is unpleasant, but useful if you do not want your c # models to depend on Json.NET.

    This also works for non-public property.

  4. Mark your object with [JsonObject(MemberSerialization = MemberSerialization.Fields)] :

     [JsonObject(MemberSerialization = MemberSerialization.Fields)] public class Test { // Remainder as before... }; 

    As explained in the documentation for MemberSerialization , MemberSerialization.Fields ensures that

    All open and closed fields are serialized. Members can be excluded using JsonIgnoreAttribute or NonSerializedAttribute. You can also set this member serialization mode by marking the class with SerializableAttribute and setting IgnoreSerializableAttribute in DefaultContractResolver to false.

    Of course, this only results in serializing non-public fields, not non-public properties, but this may be what you need if your goal is to print an arbitrary variable for debugging purposes.

  5. Use a custom contract handler that serializes all public and private fields.

    Some of them are shown in JSON.Net. Forced serialization of all private fields and all fields in subclasses that serialize both properties and fields that are public or private.

    Another, DeclaredFieldContractResolver from C # Serializing with JSON.NET-inherited private fields , serializes only public or private fields, automatically assuming all objects are marked with MemberSerialization.Fields . You would use it like this:

     var settings = new JsonSerializerSettings { ContractResolver = DeclaredFieldContractResolver.Instance }; var json = JsonConvert.SerializeObject(t1, Formatting.Indented, settings); 
  6. Create a custom JsonConverter that serializes the required fields and properties. Since the fields are private, this must be a nested type :

     public class Test { public class TestJsonConverter : JsonConverter { public override bool CanConvert(Type objectType) { return typeof(Test).IsAssignableFrom(objectType); } public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer) { var test = (Test)value; writer.WriteStartObject(); writer.WritePropertyName(nameof(Test.A)); serializer.Serialize(writer, test.A); writer.WritePropertyName(nameof(Test.b)); serializer.Serialize(writer, test.b); writer.WriteEndObject(); } public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer) { throw new NotImplementedException(); } } // Remainder as before } 

    And use it like:

     var json = JsonConvert.SerializeObject(t1, Formatting.Indented, new Test.TestJsonConverter()); 

    Although this works because the type is nested, your model will still depend on Json.NET, making option # 2 a better choice.

If you throw away your object for debugging purposes only, # 5 might be the best option.

+7
source

Source: https://habr.com/ru/post/1275488/


All Articles