C#でJSON形式のデータを出力してみた

思うところ有りまして、C#でJSON形式のデータを出力してみました。自分でJSON形式のテキストデータを作るのではなくて、シリアライザーを使ってインスタンスをJSONに変換してみました。

目次

  1. 環境
  2. JSONって?
  3. シリアライザーの準備
  4. シリアル化の手順
    1. DataContractJsonSerializerクラス
    2. DataContractJsonSerializer.WriteObjectメソッド
  5. 試してみた
    1. シリアル化するデータ
    2. コード
    3. 実行結果

環境

  • Visual Studio 2015 Express for Windows Desktop

JSONって?

JavaScript Object Notation (JSON)というのは、JavaScript発祥のデータ形式ですね。詳しくは ウィキペディア で。

実は今回初めて使ってみました。

シリアライザーの準備

シリアル化というのは、アプリ実行時のデータの実体(インスタンス)をJSON形式に変換することです。XMLでも同様にシリアル化(シリアライズ)、逆シリアル化(デシリアライズ)と言いますね。

ググるとJSON用のライブラリがいくつかあるようなのですが、今回はC#のシリアライザーを使います。

JSONシリアライザーを使用するにあたって、参照の追加が必要です。

まず、ソリューションエクスプローラーの「参照」を右クリックし、右クリックメニューの中から「参照の追加」を選択します。

参照の追加

そうするとソリューションマネージャーウィンドウが開くので、「アセンブリ」→「フレームワーク」と選択し、「System.Runtime.Serialization」にチェックを付けて、「OK」ボタンをクリックします。

アセンブリの追加

そうすると、「参照」の子にSystem.Runtime.Serializationが追加されます。

追加の結果

シリアル化の手順

MSDN に記載されている手順そのままです。

  1. 元になるデータのインスタンスを作る。

  2. メモリーストリームを作る。

  3. DataContractJsonSerializerクラスのインスタンスを作る。

  4. DataContractJsonSerializer.WriteObject(Stream, Object)メソッドで、データをメモリストリームに書き出す。

  5. メモリーストリームから出力の処理をする。

DataContractJsonSerializerクラス

DataContractJsonSerializerクラス は、JSON形式へのシリアル化と逆シリアル化をするクラスです。

今回使ったコンストラクターは下記です。

DataContractJsonSerializer(Type type)

引数

内容

type

Type

シリアル化・逆シリアル化するインスタンスの型。

他にもいろいろありますので、 DataContractJsonSerializerクラス を参照してください。

DataContractJsonSerializer.WriteObjectメソッド

DataContractJsonSerializer.WriteObject メソッド はシリアル化(インスタンス→JSON)に使用するメソッドです。

今回使った構文は下記です。

WriteObject(Stream stream, object data)

引数

内容

stream

Stream

書き込み先のストリーム。

data

object

書き込むデータを格納しているインスタンス。

試してみた

データを保持するインスタンスを作って、そのインスタンスをシリアル化して、シリアル化したJSONデータをコンソールに出力する、コンソールアプリを作ってみました。インスタンスが入れ子構造を持っているという、ちょっとひねくれた形です。

シリアル化するデータ

下図のように、SubFoldersというプロパティに自分と同じクラスのインスタンスのコレクションを持つインスタンスです。

サンプル

コード

コードは下記の様にしてみました。

using System;
using System.Runtime.Serialization;
using System.Runtime.Serialization.Json;
using System.IO;
using System.Collections.ObjectModel;

namespace json_trial
{
    class Program
    {
        static void Main(string[] args)
        {
            // JSONに変換するデータを作る。
            FolderInformation f = new FolderInformation();
            f.Name = "f";
            f.Size = 512;
            FolderInformation g = new FolderInformation();
            g.Name = "g";
            g.Size = 1024;
            f.SubFolders.Add(g);
            FolderInformation h = new FolderInformation();
            h.Name = "h";
            h.Size = 65536;
            f.SubFolders.Add(h);

            // データをJSON形式にシリアル化して、メモリーストリームに出力する。
            MemoryStream st = new MemoryStream(); // メモリーストリームを作成
            DataContractJsonSerializer serializer = new DataContractJsonSerializer(typeof(FolderInformation)); // シリアライザーを作成
            serializer.WriteObject(st, f); // シリアライザーで出力

            // メモリーストリームの内容をコンソールに出力する。
            st.Position = 0;
            StreamReader reader = new StreamReader(st);
            Console.WriteLine(reader.ReadToEnd());
        }
    }

    /// <summary>
    /// データ保持用のクラス
    /// </summary>
    [DataContract]
    public class FolderInformation
    {
        [DataMember]
        public string Name { get; set; }

        [DataMember]
        public Int64 Size { get; set; }

        private Collection<FolderInformation> _subfolders = new Collection<FolderInformation>();
        [DataMember]
        public Collection<FolderInformation> SubFolders
        {
            get { return _subfolders; }
        }
    }
}

説明を書いておこうと思いますが、シリアル化と出力部分はコメントの通りですので省きます。

データ保持用のクラスについてですが、コレクションのプロパティの設定の仕方がちょっと変わっています。上記コードのFolderInformationクラスのSubFolersプロパティのことですが、getterだけを設定してRead Onlyにしています。そして外部から参照されたときは非公開のコレクションのフィールド_subfoldersを返します。

「setterが無かったら、どうやってデータを追加するんだ?」と思ってしまうのですが、Add()メソッドでオブジェクトを追加できます。なぜでしょうか。ドット演算子とかの働きを勉強すれば良いのでしょうが、何をみたら良いかも分らないので、動作から仕組みを想像してみます。

FolderInformation f = new FolderInformation();
FolderInformation g = new FolderInformation();
f.SubFolders.Add(g);

上記のコードが実行されたとき、Add()メソッドさんはインスタンスgを追加する先として、インスタンスfのSubFoldersプロパティを参照して追加先のコレクションの実体がどこにあるのか知るのではないでしょうか。必要なのはコレクションのインスタンスがどこにあるかということなので、setterにデータを入れるのではなくて、getterからコレクションインスタンスを取得すると。

仕組み

あくまでも想像です。私はこういう風に理解することにしましたということを表明してるだけです。信じないでください。

実行結果

出力結果は下記の様になりました。

{"name":"f","Size":512,"SubFolders":[{"name":"g","Size":1024,"SubFolders":[]},{"name":"h","Size":2048,"SubFolders":[]}]}

入れ子構造で出力されてますね。

公開日

広告