为什么在尝试通过序列化为 JSON 来打印对象时缺少一些成员?

Why are some members missing when trying to print an object by serializing to JSON?(为什么在尝试通过序列化为 JSON 来打印对象时缺少一些成员?)

本文介绍了为什么在尝试通过序列化为 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 建议使用 Json.NET 进行序列化以及其他答案, 和
  • 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
  • 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 属性和字段.您的字段 Abprivate.要使 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. 公开:

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;
    }
};

只有 getter 需要公开,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] 和您的字段与 [数据成员]:

[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, MemberSerialization.Fields 确保

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.

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

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.

另一个,DeclaredFieldContractResolver,来自 C# 使用 JSON.NET 继承的私有字段进行序列化,通过自动假设所有对象都用 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 来打印对象时缺少一些成员?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持编程学习网!

  • 本文标题为:为什么在尝试通过序列化为 JSON 来打印对象时缺少一些成员?

    基础教程推荐