尝试通过序列化为JSON打印对象时,为什么有些成员会丢失? [英] Why are some members missing when trying to print an object by serializing to JSON?

查看:99
本文介绍了尝试通过序列化为JSON打印对象时,为什么有些成员会丢失?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

How to print any arbitrary variable in C# so as to print all members?

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

I found three answers with the same technique:

  • https://stackoverflow.com/a/26181763/2125837 which suggests serializing with Json.NET among other answers, and
  • https://tech.io/playgrounds/2098/how-to-dump-objects-in-c/using-json-and-yaml-serializers,
  • https://www.codeproject.com/Articles/1194980/How-to-Dump-Object-for-Debugging-Purposes-in-Cshar

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

However, when I tried it out, 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);
    }
}

我得到的都是空的Test输出:

All that I got are empty Test outputs:

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

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

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

推荐答案

默认情况下,Json.NET只会序列化 public 属性和字段.您的字段Ab私有.要使Json.NET序列化非公共(私有或内部)成员,您可以:

By default Json.NET will only serialize public properties and fields. Your fields A and b are private. To cause nonpublic (private or internal) members to be serialized by Json.NET, you can:

  1. 将其公开:

  1. Make them public:

public int A;
public int b;

但是,从风格上讲,如果要使其公开,最好将它们转换为属性:

However, stylistically, if you are going to make them be public, it's better to convert them to 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;
    }
};

对于Json.NET,只有获取器需要公开才能序列化它们.

Only the getters need be public for Json.NET to serialize them.

然后用[JsonProperty]标记:

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

这也适用于非公共财产.

This works for nonpublic properties as well.

使用 [DataContract] [DataMember] :

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

请注意,数据合同序列化是可选的,因此您需要标记每个成员以使用[DataMember]进行序列化.有点麻烦,但如果您不希望c#模型依赖于Json.NET,则很有用.

Note that data contract serialization is opt-in so you will need to mark every member to be serialized with [DataMember]. Kind of a nuisance but useful if you don't want your c# models to have a dependency on Json.NET.

这也适用于非公共财产.

This also works for nonpublic properties.

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

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

MemberSerialization文档中所述, c9>确保

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

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

All public and private fields are serialized. Members can be excluded using JsonIgnoreAttribute or NonSerializedAttribute. This member serialization mode can also be set by marking the class with SerializableAttribute and setting IgnoreSerializableAttribute on DefaultContractResolver to false.

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

Of course this only causes nonpublic fields to be serialized, not nonpublic properties, but this may be what you want if your purpose is to print an arbitrary variable for debugging purposes.

使用自定义合同解析器来序列化所有公共和非公共领域.

Use custom contract resolver that serializes all public and nonpublic fields.

几个显示在 JSON.Net:强制序列化所有私有字段和子类中的所有字段 ,可同时序列化公共属性或私有属性和字段.

Several are shown at JSON.Net: Force serialization of all private fields and all fields in sub-classes which serialize both properties and fields that are public or private.

另一个,来自 使用JSON.NET继承的私有字段进行C#序列化的DeclaredFieldContractResolver ,通过自动假定所有对象都标记为MemberSerialization.Fields,仅序列化公共或私有字段.您将像这样使用它:

Another, DeclaredFieldContractResolver from C# Serialize with JSON.NET inherited private fields, serializes only fields that are public or private by 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);

  • 创建一个序列化的自定义JsonConverter 必要的字段和属性.由于这些字段是私有字段,因此必须为嵌套类型:

    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
    }
    

    并像这样使用它:

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

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

    While this works, since the type is nested your model will still have a dependency on Json.NET, which makes option #2 the better choice.

    如果仅出于调试目的转储对象,则#5可能是最佳选择.

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

    这篇关于尝试通过序列化为JSON打印对象时,为什么有些成员会丢失?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

  • 查看全文
    登录 关闭
    扫码关注1秒登录
    发送“验证码”获取 | 15天全站免登陆