C# 类的自定义 Json 序列化

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/11934487/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-09 19:46:28  来源:igfitidea点击:

Custom Json Serialization of class

c#jsonjson.net

提问by Dinesh Ahuja

I have code structured like below.

我的代码结构如下。

public class Stats
{
        public string URL { get; set; }
        public string Status { get; set; }
        public string Title { get; set; }
        public string Description { get; set; }
        public int Length { get; set; }
}

and

 public class UrlStats
 {
        public string URL { get; set; }
        public int TotalPagesFound { get; set; }
        public List<Stats> TotalPages { get; set; }
        public int TotalTitleTags { get; set; }
        public List<Stats> TotalTitles { get; set; }
        public int NoDuplicateTitleTags { get; set; }
        public List<Stats> DuplicateTitles { get; set; }
        public int NoOverlengthTitleTags { get; set; }
        public List<Stats> OverlengthTitles { get; set; }
 }

Basically i am scanning a website for statistics like title tags, duplicate titles, etc.

基本上,我正在扫描一个网站以获取诸如标题标签、重复标题等统计信息。

I am using JQuery and making AJAX calls to webservice and retrieving url stats while the process is running to show user url stats by far collected since it takes quite a time to scan a big website. So after every 5 seconds i retrieve stats from server. Now the problem is all the List variable data i need to send at the end when scanning processing is complete, not during updates. What's happening right now the List<Stats>variable data is also sent during updates which is big chunk of data and i want to send only inttype variables which are required to show process updates.

我正在使用 JQuery 并对 webservice 进行 AJAX 调用并在进程运行时检索 url 统计信息以显示迄今为止收集的用户 url 统计信息,因为扫描一个大网站需要相当长的时间。所以每 5 秒后我从服务器检索统计信息。现在的问题是我需要在扫描处理完成时而不是在更新期间发送的所有 List 变量数据。现在发生了什么,List<Stats>在更新期间也会发送变量数据,这是大块数据,我只想发送int显示流程更新所需的类型变量。

From searching on internet i couldn't find anything useful solving my problem and i found that Json.NET is very good library but i really don't know how to properly use it to get what i want.

通过在互联网上搜索,我找不到任何有用的东西来解决我的问题,我发现 Json.NET 是一个非常好的库,但我真的不知道如何正确使用它来获得我想要的。

Basically i am looking for serializing properties depending on their datatype at runtime, if its possible.

基本上,如果可能的话,我正在根据它们在运行时的数据类型寻找序列化属性。

采纳答案by fero

There are two different approaches for your problem.

您的问题有两种不同的方法。

You should choose the first one if you are going to change your classes more often because the first approach prevents that you forget to serialize a newly added property. Furthermore it is much more reusable if you want to add another classes you want to be serialized the same way.

如果您要更频繁地更改类,则应选择第一种方法,因为第一种方法可防止您忘记序列化新添加的属性。此外,如果您想添加另一个要以相同方式序列化的类,它的可重用性要高得多。

If you have only these two classes and it's most likely that they're not going to change you can choose the second approach to keep your solution simple.

如果您只有这两个类并且它们很可能不会改变,您可以选择第二种方法来保持您的解决方案简单。

1. Use a custom converter to select all intproperties

1.使用自定义转换器选择所有int属性

The first approach is to use a custom JsonConverterwhich serializes a class or struct by only including properties which have type int. The code might look like this:

第一种方法是使用自定义JsonConverter,它通过仅包含具有 type 的属性来序列化类或结构int。代码可能如下所示:

class IntPropertyConverter : JsonConverter
{
    public override bool CanConvert(Type objectType)
    {
        // this converter can be applied to any type
        return true;
    }

    public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
    {
        // we currently support only writing of JSON
        throw new NotImplementedException();
    }

    public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
    {
        if (value == null)
        {
            serializer.Serialize(writer, null);
            return;
        }

        // find all properties with type 'int'
        var properties = value.GetType().GetProperties().Where(p => p.PropertyType == typeof(int));

        writer.WriteStartObject();

        foreach (var property in properties)
        {
            // write property name
            writer.WritePropertyName(property.Name);
            // let the serializer serialize the value itself
            // (so this converter will work with any other type, not just int)
            serializer.Serialize(writer, property.GetValue(value, null));
        }

        writer.WriteEndObject();
    }
}

Then you have to decorate your class with a JsonConverterAttribute:

然后你必须用一个装饰你的班级JsonConverterAttribute

[JsonConverter(typeof(IntPropertyConverter))]
public class UrlStats
{
    // ...
}

Disclaimer:This code has been tested only very roughly.

免责声明:此代码仅经过非常粗略的测试。



2. Choose properties individually

2. 单独选择属性

The second solution looks a bit simpler: You can use the JsonIgnoreAttributeto decorate the attributes you want to exclude for serialization. Alternatively you can switch from "blacklisting" to "whitelisting" by explicitly including the attributes you want to serialize. Here is a bit of sample code:

第二种解决方案看起来更简单:您可以使用JsonIgnoreAttribute来装饰要排除以进行序列化的属性。或者,您可以通过显式包含要序列化的属性从“黑名单”切换到“白名单”。这是一些示例代码:

Blacklisting:(I've reordered the properties for a better overview)

黑名单:(我重新排列了属性以获得更好的概览)

[JsonObject(MemberSerialization.OptOut)] // this is default and can be omitted
public class UrlStats
{
    [JsonIgnore] public string URL { get; set; }
    [JsonIgnore] public List<Stats> TotalPages { get; set; }
    [JsonIgnore] public List<Stats> TotalTitles { get; set; }
    [JsonIgnore] public List<Stats> DuplicateTitles { get; set; }
    [JsonIgnore] public List<Stats> OverlengthTitles { get; set; }

    public int TotalPagesFound { get; set; }
    public int TotalTitleTags { get; set; }
    public int NoDuplicateTitleTags { get; set; }
    public int NoOverlengthTitleTags { get; set; }
}

Whitelisting:(also reordered)

白名单:(也重新排序)

[JsonObject(MemberSerialization.OptIn)] // this is important!
public class UrlStats
{
    public string URL { get; set; }
    public List<Stats> TotalPages { get; set; }
    public List<Stats> TotalTitles { get; set; }
    public List<Stats> DuplicateTitles { get; set; }
    public List<Stats> OverlengthTitles { get; set; }

    [JsonProperty] public int TotalPagesFound { get; set; }
    [JsonProperty] public int TotalTitleTags { get; set; }
    [JsonProperty] public int NoDuplicateTitleTags { get; set; }
    [JsonProperty] public int NoOverlengthTitleTags { get; set; }
}

回答by corrego

Oh got it, re-reading your question I think you can serialize a projection of your data.

哦,明白了,重新阅读您的问题,我认为您可以序列化数据的投影。

You can try the following:

您可以尝试以下操作:

var json = JsonConvert.SerializeObject(new { u.TotalPagesFound, u.TotalTitleTags, u.NoDuplicateTitleTags, u.NoOverlengthTitleTags } );

This will convert to JSON only the int properties of your class. This is the easiest way, and it is tied to the structure of your class. If you want something more general, you will need to implement a custom converter.

这将仅将您的类的 int 属性转换为 JSON。这是最简单的方法,它与类的结构有关。如果你想要更一般的东西,你需要实现一个自定义转换器。

Original answer:

原答案:

I see no problem with your classes, you don't have anything weird like loop references, so Json.NET should have no problem serializing your class. So go grab Json.NET and then you can attempt the following

我认为你的类没有问题,你没有像循环引用这样的奇怪的东西,所以 Json.NET 序列化你的类应该没有问题。所以去抓住 Json.NET 然后你可以尝试以下

// create new instance of your url stat class
var u = new UrlStats() { URL = "a.com", TotalPages = new List<Stats>() { new Stats() { URL = "b.com", Status = "xxxx" } } };
// seralize!
var json = JsonConvert.SerializeObject(u);
Console.Write(json);

What I get with this method is something like this:

我用这种方法得到的是这样的:

{"URL":"a.com","TotalPagesFound":0,"TotalPages":[{"URL":"b.com","Status":"xxxx","Title":null,"Description":null,"Length":0}],"TotalTitleTags":0,"TotalTitles":null,"NoDuplicateTitleTags":0,"DuplicateTitles":null,"NoOverlengthTitleTags":0,"OverlengthTitles":null}

And that looks like good json to me.

对我来说,这看起来像是很好的 json。