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統計を取得して、大きなWebサイトをスキャンするのにかなりの時間がかかるため、収集されたユーザーのURL統計を表示しています。したがって、5秒ごとにサーバーから統計を取得します。問題は、更新中ではなく、スキャン処理が完了したときに最後に送信する必要があるすべてのリスト変数データです。現在起こっていることは、変数データも更新中に送信されますが、これはデータの大きな塊であり、プロセスの更新を表示するために必要な型変数List<Stats>のみを送信したいと考えています。int

インターネットで検索したところ、問題を解決するのに役立つものは何も見つかりませんでした.Json.NETは非常に優れたライブラリであることがわかりましたが、それを適切に使用して必要なものを取得する方法が本当にわかりません.

基本的に、可能であれば、実行時のデータ型に応じてプロパティをシリアル化することを探しています。

4

2 に答える 2

36

あなたの問題には2つの異なるアプローチがあります。

クラスをより頻繁に変更する場合は、最初のアプローチを選択する必要があります。最初のアプローチでは、新しく追加されたプロパティをシリアル化するのを忘れるのを防ぐためです。さらに、同じ方法でシリアライズしたい別のクラスを追加したい場合は、はるかに再利用可能です。

これら 2 つのクラスしかなく、変更される可能性がほとんどない場合は、2 番目のアプローチを選択してソリューションをシンプルに保つことができます。

1. カスタム コンバーターを使用してすべてのintプロパティを選択する

最初のアプローチは、JsonConvertertype を持つプロパティのみを含めることによってクラスまたは構造体をシリアル化するカスタムを使用すること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. プロパティを個別に選択する

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 に答える