尝试通过序列化为JSON打印对象时,为什么有些成员丢失?

xpt*_*xpt 2 c# json json.net

如何在C#中打印任意变量以便打印所有成员?

我用相同的技术找到了三个答案:

但是,当我尝试使用以下代码时,

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);
    }
}
Run Code Online (Sandbox Code Playgroud)

我得到的只是空Test输出:

{}
{}
System.Collections.Generic.List`1[Program+Test]
[
  {},
  {},
  {}
]
Run Code Online (Sandbox Code Playgroud)

使用Json.NET序列化为JSON时,为什么我的所有类成员都丢失了?

dbc*_*dbc 7

默认情况下,Json.NET只会序列化公共属性和字段.你的领域A,并b私人.要使非公共(私有或内部)成员通过Json.NET序列化,您可以:

  1. 公开他们:

    public int A;
    public int b;
    
    Run Code Online (Sandbox Code Playgroud)
  2. 马克然后用[JsonProperty]:

    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;
        }
    };
    
    Run Code Online (Sandbox Code Playgroud)
  3. 使用以下内容标记您的对象[DataContract]和您的字段[DataMember]:

    [JsonProperty]
    int A;
    [JsonProperty]
    int b;
    
    Run Code Online (Sandbox Code Playgroud)

    请注意,数据协定序列化是选择性的,因此您需要标记要序列化的每个成员[DataMember].如果你不希望你的c#模型依赖于Json.NET,那会有点麻烦但很有用.

  4. 标记您的对象[JsonObject(MemberSerialization = MemberSerialization.Fields)]:

    [DataContract]
    public class Test
    {
        [DataMember]
        int A;
        [DataMember]
        int b;
        public Test(int _a, int _b)
        {
            A = _a;
            b = _b;
        }
    };
    
    Run Code Online (Sandbox Code Playgroud)

    由于在解释文件MemberSerialization,MemberSerialization.Fields可确保

    所有公共和私有字段都是序列化的.可以使用JsonIgnoreAttribute或NonSerializedAttribute排除成员.也可以通过使用SerializableAttribute标记类并将DefaultContractResolver上的IgnoreSerializableAttribute设置为false来设置此成员序列化模式.

    当然,这只会导致非公共字段被序列化,而不是非公共属性,但如果您的目的是打印任意变量以进行调试,则可能是您想要的.

  5. 使用序列化所有公共和非公共字段的自定义合同解析程序.

    JSON.Net上显示了几个:强制序列化所有私有字段和子类中的所有字段,这些字段序列化公共或私有属性和字段.

    另一个DeclaredFieldContractResolver来自c#Serialize和JSON.NET继承的私有字段,通过自动假设所有对象都被标记来序列化公共或私有字段MemberSerialization.Fields.你会像这样使用它:

    [JsonObject(MemberSerialization = MemberSerialization.Fields)]
    public class Test
    {
        // Remainder as before...
    };
    
    Run Code Online (Sandbox Code Playgroud)
  6. 创建一个序列化必要字段的自定义JsonConverter.由于字段是私有的,因此需要是嵌套类型:

    var settings = new JsonSerializerSettings
    {
        ContractResolver = DeclaredFieldContractResolver.Instance
    };
    var json = JsonConvert.SerializeObject(t1, Formatting.Indented, settings);
    
    Run Code Online (Sandbox Code Playgroud)

    并使用它像:

    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
    }
    
    Run Code Online (Sandbox Code Playgroud)

    虽然这样可行,但由于类型是嵌套的,因此您的模型仍然依赖于Json.NET,这使得选项#2成为更好的选择.

如果您只是为了调试目的而转储对象,那么#5可能是最佳选择.