25

我的代码结构如下。

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<Stats>变量数据也在更新期间发送,这是一大块数据,我只想发送int显示流程更新所需的类型变量。

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

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

4

2 回答 2

36

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

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

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

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; }
}
于 2012-08-14T13:49:08.980 回答
3

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

您可以尝试以下方法:

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

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

原答案:

我认为你的类没有问题,你没有任何奇怪的循环引用,所以 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);

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

{"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}

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

于 2012-08-13T14:06:51.830 回答