試験運用中なLinux備忘録・旧記事

はてなダイアリーで公開していた2007年5月-2015年3月の記事を保存しています。

C#のテストを兼ねた静的メンバのテスト

Pythonにおけるクラスの静的メンバについて」で静的メンバについて扱ったが、Pythonはその扱い方は特殊な例に入ると思われる。
ここではそれと同じことをC#という言語で書いてみることにする。
なお、C#については初心者で全く詳しくないので、色々なテストも同時に行っている。また、コメントも多めに書いている。

using System;


/*
 * 名前空間TestNSのクラスFooはTestNS.Foo
 *「using [名前空間名];」を記述するとその部分を省略できる
 *「System.Console.WriteLine()」は「using System;」を記述すると「Console.WriteLine()」と書ける
 */
namespace TestNS
{
  /*
   * Inline XML Documentationによるコメント
   * summary要素は概要のコメントとなる
   * MonoDevelopでは「///」を書くと「///<summary>」から「///</summary>」までが入力される
   * また、引数や戻り値に関する記述も自動で追加してくれる
   * その他、タグ名(remarksなど)の補完も可能
   * プロジェクトのオプション設定で「Release」「Debug」ごとにXMLドキュメント生成のオプションが指定できる
   */
  /// <summary>最小限構成のクラス</summary>
  /// <remarks>このクラスは「何もしない」というはたらきをします</remarks>
  class Foo
  {
  }
}


namespace Hello
{
  /// <summary>テストクラス</summary>
  /// <remarks>このクラスでは静的メンバのテストを含んだC#の基本的なテストを行っています</remarks>
  class TestClass
  {
    /*
     * staticの付いた静的メンバ変数/関数は各オブジェクトが持つデータとは無関係なデータや処理で
     * [クラス名].[静的メンバ変数/関数]として使用
     */
    /// <summary>オブジェクトの数</summary>
    /// <remarks>コンストラクタが呼ばれた数を保持しています</remarks>
    private static int cnt = 0; // private付き(省略時もprivate扱い)のメンバは外部から直接参照できない
    /* クラス名と同名のメンバ関数(コンストラクタ)はオブジェクト生成時の初期化処理として使用される */
    /// <summary>コンストラクタ</summary>
    /// <remarks>
    /// 本クラスのオブジェクトが作られると実行される処理です
    /// メンバ変数cntを1増やして標準出力にその値とコンストラクタ引数を含めて出力します
    /// </remarks>
    /// <param name="str">標準出力に追加で出力する文字列 <see cref="System.String"/></param>
    public TestClass (string str)  // public付きのメンバは外部から直接参照できる
    {
      cnt++;  /* コンストラクタが呼ばれた数を保持するものとする */
      Console.WriteLine ("TestClass(): cnt={0} str={1}", cnt, str);  // 「{0}, {1}, {2}, ...」に後ろの引数が順に入る
    }
    /// <summary>メンバ変数cntを返す</summary>
    /// <remarks>本クラスから作成された全てのオブジェクトが共有している値cntを返します</remarks>
    /// <returns>静的メンバ変数cnt <see cref="System.Int32"/></returns>
    public int get_obj_count ()
    {
      /*
       * 直接公開(public)メンバ変数を参照するのではなく
       * 公開メンバ関数から戻り値として非公開(private)メンバ変数を取り出す形が多い
       */
      return cnt;
    }
    /*
     * オブジェクトが持つ値とは関係がないがクラスに含めたい関数は
     * 静的メンバ関数として「public static」を付ける(「private static」では使えない)
     */
    /// <summary>2つの整数値のうち大きいほうを返す</summary>
    /// <remarks>渡された2つの整数値のうち大きいほうの値を返します</remarks>
    /// <param name="a">1つ目の整数 <see cref="System.Int32"/></param>
    /// <param name="b">2つ目の整数 <see cref="System.Int32"/></param>
    /// <returns>大きいほうの値 <see cref="System.Int32"/></returns>
    public static int max (int a, int b)
    {
      return (a < b) ? b : a;  // 「丸括弧内の条件が真なら「?」の右、偽なら「:」の右」を返す
    }
  }

  /// <summary>メイン処理のクラス</summary>
  /// <remarks>このクラスではメイン処理を行います</remarks>
  class MainClass
  {
    /*
     * 静的メンバ関数Main()から処理が始まる
     * 戻り値を返す(return文を書く)場合はint、返さない場合はvoid
     */
    /// <summary>メイン処理</summary>
    /// <remarks>プログラムの最初に実行される処理です</remarks>
    /// <param name="args">コマンド行引数の文字列の配列 <see cref="System.String"/></param>
    /// <returns>終了ステータス(正常:0 異常:1とする) <see cref="System.Int32"/></returns>
    public static int Main (string[] args)  // publicかつstaticで名前Mainである必要がある
    {
      /* System.Console.WriteLine()は標準出力に改行付きで出力 */
      Console.WriteLine ("Hello, Work!");
      if (args.Length > 3)  // 配列argsの長さがargs.Length
      {
         /* 構文内の処理が複数行だと波括弧が必要 */
        Console.WriteLine ("Too many arguments");
        return 1;
      }
      /*
       * foreach文はPythonのfor文に近い構文・各コマンド行引数を行ごとに表示
       * 構文内の処理が1行だと波括弧は不要
       */
      foreach (string arg in args)  // argはこの構文内でのみ使える
        Console.WriteLine ("arg:" + arg); // 「+」は文字列連結
      /*
       * 「[オブジェクト] = new [クラス名]([コンストラクタ引数...]);」の書式で
       * クラスからオブジェクト(インスタンス)を作成
       * 宣言済みでない場合は下のように先頭にクラス名を付けて同時に宣言をする
       */
      TestNS.Foo foo = new TestNS.Foo ();  /* 本プログラムで今後使わないため警告の原因となっている */
      TestClass tst1 = new TestClass ("aaa");
      TestClass tst2 = new TestClass ("bbb");
      TestClass tst3 = new TestClass ("ccc");
      /*
       * 静的メンバ変数cntを参照
       * 全てのオブジェクトが同じ値を共有しているのが分かる
       */
      Console.WriteLine ("tst1.get_obj_count(): {0}", tst1.get_obj_count ());
      Console.WriteLine ("tst2.get_obj_count(): {0}", tst2.get_obj_count ());
      Console.WriteLine ("tst3.get_obj_count(): {0}", tst3.get_obj_count ());
      /*
       * 静的メンバ関数を呼び出す
       */
      Console.WriteLine ("TestClass.max(3, 5): {0}", TestClass.max (3, 5));
      Console.WriteLine ("TestClass.max(6, 6): {0}" , TestClass.max (6, 6));
      Console.WriteLine ("TestClass.max(15, 7): {0}", TestClass.max (15, 7));
      return 0;
    }
  }
}

(2009/3/22)コメントを微調整
下は実行結果。「Pythonにおけるクラスの静的メンバについて」の結果がこれと同じようになったことが分かる。

Hello, Work!
TestClass(): cnt=1 str=aaa
TestClass(): cnt=2 str=bbb
TestClass(): cnt=3 str=ccc
tst1.get_obj_count(): 3
tst2.get_obj_count(): 3
tst3.get_obj_count(): 3
TestClass.max(3, 5): 5
TestClass.max(6, 6): 6
TestClass.max(15, 7): 15

また、3つまでの数の引数が渡されたときには

Hello, Work!
arg:a
arg:b
arg:c
TestClass(): cnt=1 str=aaa
(以下略)

のようにそれぞれの項目が「arg:」の後ろに表示され、4つ以上の引数を付けて実行した場合は

Hello, Work!
Too many arguments

となり終了ステータス1がシェルなどに返る。

関連記事: