一尘不染

类的自定义Json序列化

json

我的代码结构如下。

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

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

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

我正在使用JQuery并向Web服务进行AJAX调用并检索url统计信息,而该过程正在运行以显示到目前为止收集的用户url统计信息,因为扫描大型网站需要花费大量时间。因此,每隔5秒,我就会从服务器检索统计信息。现在的问题是我需要在扫描处理完成时(而不是更新期间)最后发送所有List变量数据。现在发生了什么事,List<Stats>变量数据也在更新期间发送,这是一大块数据,我只想发送int显示过程更新所需的类型变量。

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

基本上,我正在寻找在运行时根据属性的数据类型对属性进行序列化的方法。


阅读 303

收藏
2020-07-27

共1个答案

一尘不染

有两种不同的方法可以解决您的问题。

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

如果只有这两个类,并且很可能它们不会更改,则可以选择第二种方法来简化解决方案。

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

第一种方法是使用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();
    }
}

然后,您必须使用来装饰类JsonConverterAttribute

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

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


2.分别选择属性

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

黑名单:( 为了更好的概述,我对属性进行了重新排序)

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

白名单:( 也已重新排序)

[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; }
}
2020-07-27