2006-05-10 (Wed)

* 現在実行中のメソッド名を取得する MethodBase.GetCurrentMethod()

この記事の直リンクURL: Permlink | この記事が属するカテゴリ: [.net] [C#]

.NET で現在実行中のメソッド名を取得するには、System.Reflection.MethodBase.GetCurrentMethod().Name を使う。

- トレース出力のために現在実行中のメソッド名を取得したい

アプリケーションの実行状態の追跡のため、メソッドの頭でメソッド名やそのときの時刻などをトレース出力したい。

トレースしたいメソッドが3個くらいしかなければ、以下のようにメソッド名を直書きしてもいいけど、タイプミスしたり、リファクタリングしてメソッド名が変わったときに修正する手間がかかってしまうのは困る。

Trace.WriteLine(DateTime.Now.ToString() + " PlayVideoClip");

メソッド名はリフレクションを使って取得できるので、とりあえず System.Reflection.MethodBase.GetCurrentMethod().Name を使うことにした。

Trace.WriteLine(DateTime.Now.ToString() + " " + System.Reflection.MethodBase.GetCurrentMethod().Name);

using System.Reflection; しておけば MethodBase.GetCurrentMethod().Name で済むけど、トレースしたいところにペタペタとコピー & ペーストすることを考えて、完全な名前で書いた。

うーん。でも、そもそもこれをコピー & ペーストする手間が煩雑で困るな。今回はこれで良かったけど、今後もコピペを繰り返すのは美しくないなあ。

メソッドにコンストラクタやデストラクタみたいな仕組みがあって、そこでトレース出力できるといいのに。ASP.NET のパイプライン処理モデルみたいな仕組みがメソッド自体に備わってるような感じ。ちょっと仕組みが大げさだから無いような気もするけど、調べてみよう。

2006-05-07 (Sun)

* アプリケーションを終了させるには Environment.Exit()

この記事の直リンクURL: Permlink | この記事が属するカテゴリ: [.net] [C#]

C# でアプリケーションを終了させるには System.Environment.Exit() を使う。

Environment.Exit(0);

Exit メソッドの引数にアプリケーションの終了コードを指定できる。これは 2005-01-20 「C# でアプリケーションの終了コードを返す」でも書いた。正常終了なら 0 を指定するのが慣例。それ以外の場合はアプリケーションの作りによって値の使い方は千差万別。呼び出し側にエラーを伝えるために、エラーに応じて細かく番号を決めておくこともある。一方、エラーはみんな終了コード1と割り切って定義することもある。

System.Windows.Forms.Application.Exit() というのもあるが、これはメッセージループを止めるだけでそれ以外の処理は続行してしまう。

今回はこれに関する失敗をした。業務エラー発生時にダイアログを出して WinForm アプリケーションを終わらせようとしたけど、Application.Exit() を使ってしまったために処理が続行されてしまった。テストしてすぐに気づいたけどね。

2006-05-03 (Wed)

* C# と DirectX で動画を再生する

この記事の直リンクURL: Permlink | この記事が属するカテゴリ: [.net] [C#] [Windows]

2006-04-27 「C# でスクリーンセーバーを作る」の続き。C# から DirectX を使って MPEG2 の動画を再生する。

- DirectX SDK のダウンロード

動画再生部分は DirectX を使って作ることにしたので、DirectX SDK をダウンロードした。サイズが390.2MB もあるので、気長に。

DirectX SDK - (April 2006)
http://www.microsoft.com/downloads/details.aspx?FamilyId=7AB ...

ダウンロードしたファイルを実行。インストーラではいつも通り「次へ」を連打してインストール完了。

- Microsoft.DirectX.AudioVideoPlayback で動画を再生

動画再生部分は Microsoft.DirectX.AudioVideoPlayback を使って簡単に作れた。

string path = GetNextClipPath();
fileIndex++;
if (videoClip == null) {
    videoClip = new Video(path);
} else {
    videoClip.Ending -= this.ClipEnded;
    videoClip.Open(path);
}
videoClip.Ending += new System.EventHandler(this.ClipEnded);
videoClip.Owner = this;
videoClip.Fullscreen = false;
Bounds = new Rectangle(0, 20, 1280, 960);
videoClip.Play();

これをベースとしている Visual Studio 2005 のスクリーンセーバースタートキットに組み込めば、動画を再生するスクリーンセーバーのできあがり。とっても簡単だ。

プログラムに名前を付けよう。スタートキットがデフォルトで付ける ScreenSaver1.exe だと味気ないし、「画面のプロパティ」で選択するときも何か名前が表示されてほしいし。とくに思いつかなかったので、とりあえず SaveTheQueen (セーブザクイーン) にした。FF12 に出てきた剣の名前が元ねただ。FF9 にも出てきたかな? もともと 2006-04-20 の「FF12 のムービーをリッピング (ripping) して再生」でリップしたファイルを再生するスクリーンセーバーを作るのが目的だから、save という単語が入っていて、FF っぽい名前であればなんでも良かった。

- SaveTheQueen のソース

後の私も含めて、誰かの参考になるかもしれないので、メインフォームとオプションフォームのコードを全部載せておく。私の環境以外を考慮していないコードだし、エラー処理やオプションの処理も入ってない。たとえばビデオクリップのパスに対して FileExists() もしてない。

ソース一式とバイナリをパッケージしたものはそのうち作ろうかな。Suversion から 自動でチェックアウトしてビルドして ClickOnce としてパッケージするようにしよう。

ScreenSaverForm.cs
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Drawing;
using System.IO;
using System.Windows.Forms;
using Microsoft.DirectX.AudioVideoPlayback;

namespace SaveTheQueen {
    partial class ScreenSaverForm : Form {

        private bool isActive = false;
        private Point mouseLocation;
        private Video videoClip;
        private DefaultTraceListener dtl;

        /// <summary>
        /// 再生するリスト上の現在位置。始点は0。
        /// </summary>
        private int fileIndex = 0;

        public ScreenSaverForm() {
            Trace.WriteLine(DateTime.Now.ToString() + " " + System.Reflection.MethodBase.GetCurrentMethod().Name);

            dtl = (DefaultTraceListener)Trace.Listeners["Default"];
            dtl.LogFileName = @"c:\trace.txt";

            InitializeComponent();
            SetupScreenSaver();
            PlayVideoClip();
        }

        private void SetupScreenSaver() {
            Trace.WriteLine(DateTime.Now.ToString() + " " + System.Reflection.MethodBase.GetCurrentMethod().Name);

            // ダブル バッファを使用して、表示パフォーマンスを改善します。
            this.SetStyle(ControlStyles.OptimizedDoubleBuffer | ControlStyles.UserPaint | ControlStyles.AllPaintingInWmPaint, true);

            // マウスをキャプチャします。
            this.Capture = true;

            // アプリケーションを全画面表示モードに設定して、マウスを表示しません。
            Cursor.Hide();
            // Bounds = Screen.PrimaryScreen.Bounds;
            ShowInTaskbar = false;
            DoubleBuffered = true;

            ResumeVideoClip();
        }

        /// <summary>
        /// 現在再生しているビデオクリップの情報を保存します。
        /// </summary>
        private void SaveVideoClip() {
            Properties.Settings.Default.LastClipIndex = fileIndex - 1;
            Properties.Settings.Default.LastClipPosision = videoClip.CurrentPosition;
            Properties.Settings.Default.Save();
        }

        /// <summary>
        /// 前回終了時に再生していたビデオクリップの情報を復元します。
        /// </summary>
        private void ResumeVideoClip() {
            int lastClipIndex = Properties.Settings.Default.LastClipIndex;
            if (0 <= lastClipIndex && lastClipIndex < Properties.Settings.Default.videoClipPath.Length) {
                fileIndex = lastClipIndex;
            }
      }

        private void PlayVideoClip() {
            Trace.WriteLine(DateTime.Now.ToString() + " " + System.Reflection.MethodBase.GetCurrentMethod().Name );

            string path = GetNextClipPath();
            fileIndex++;
            if (videoClip == null) {
                videoClip = new Video(path);
            } else {
                videoClip.Ending -= this.ClipEnded;
                videoClip.Open(path);
            }
            videoClip.Ending += new System.EventHandler(this.ClipEnded);
            videoClip.Owner = this;
            videoClip.Fullscreen = false;
            // WindowState = FormWindowState.Normal;
            Bounds = new Rectangle(0, 20, 1280, 960);
            videoClip.Play();
        }

        private void ClipEnded(object sender, System.EventArgs e) {
            Trace.WriteLine(DateTime.Now.ToString() + " " + System.Reflection.MethodBase.GetCurrentMethod().Name);

            PlayVideoClip();
        }

        private string GetNextClipPath() {
            Trace.WriteLine(DateTime.Now.ToString() + " " + System.Reflection.MethodBase.GetCurrentMethod().Name);

            if (Properties.Settings.Default.videoClipPath.Length == 0) {
                return "";
            }
            if (Properties.Settings.Default.videoClipPath.Length - 1 < fileIndex) {
                fileIndex = 0;
            }
            if (fileIndex < 0) {
                fileIndex = Properties.Settings.Default.videoClipPath.Length - 1;
            }

            string path = Properties.Settings.Default.videoClipPath[fileIndex];
            Trace.WriteLine(DateTime.Now.ToString() + " " + System.Reflection.MethodBase.GetCurrentMethod().Name + " " + path);

            return path;
        }

        private void ScreenSaverForm_MouseMove(object sender, MouseEventArgs e) {
            Trace.WriteLine(DateTime.Now.ToString() + " " + System.Reflection.MethodBase.GetCurrentMethod().Name);

            // IsActive および MouseLocation を、このイベントが最初に呼び出されるときにのみ設定します。
            if (!isActive) {
                mouseLocation = MousePosition;
                isActive = true;
            } else {
                // 最初の呼び出し以来マウスが著しく移動した場合、閉じます。
                if ((Math.Abs(MousePosition.X - mouseLocation.X) > 10) ||
                    (Math.Abs(MousePosition.Y - mouseLocation.Y) > 10)) {
                    Close();
                }
            }
        }

        private void ScreenSaverForm_KeyDown(object sender, KeyEventArgs e) {
            Trace.WriteLine(DateTime.Now.ToString() + System.Reflection.MethodBase.GetCurrentMethod().Name);

            if (e.KeyData == Keys.F) {
                // 次のクリップ
                PlayVideoClip();
            } else if (e.KeyData == Keys.B) {
                // 前のクリップ
                fileIndex -= 2;
                PlayVideoClip();
            } else if (e.KeyData == Keys.R) {
                // 現在再生中のクリップを頭からもう一度再生
                fileIndex--;
                PlayVideoClip();
            } else {
                Close();
            }
        }

        private void ScreenSaverForm_MouseDown(object sender, MouseEventArgs e) {
            Trace.WriteLine(DateTime.Now.ToString() + System.Reflection.MethodBase.GetCurrentMethod().Name);

            Close();
        }

        private void ScreenSaverForm_FormClosing(object sender, FormClosingEventArgs e) {
            Trace.WriteLine(DateTime.Now.ToString() + " " + System.Reflection.MethodBase.GetCurrentMethod().Name);

            if (videoClip != null) {
                SaveVideoClip();
                videoClip.Dispose();
                videoClip = null;
            }
        }
    }
}

ダブルバッファなどはベースとしたスクリーンセーバースタートキットに最初から入ってたもの。効果のほどは不明。コメントアウトしても問題なく再生できてたし。CPU 負荷や GPU の負荷が違うのかな。タスクマネージャで見てたけど、コメントアウトしても負荷が十分に低かったので違いがわからなかった。

OptionsForm.cs
using System;
using System.Configuration;
using System.Drawing;
using System.Windows.Forms;


namespace SaveTheQueen {
    partial class OptionsForm : Form {
        public OptionsForm() {
            InitializeComponent();

            // 現在の設定からテキスト ボックスを読み込みます。
            try {
                backgroundImageFolderTextBox.Lines = Properties.Settings.Default.videoClipPath;
            //  rssFeedTextBox.Text = Properties.Settings.Default.RssFeedUri;
            } catch {
                MessageBox.Show("スクリーン セーバーの設定での読み取り中に問題が発生しました。");
            }
        }

        // [適用] ボタンが最後に押されてから変更が行われた場合にのみ、
        // [適用] ボタンをアクティブな状態に更新します。
        private void UpdateApply() {
            /*
            if (Properties.Settings.Default.BackgroundImagePath != backgroundImageFolderTextBox.Text
                  || Properties.Settings.Default.RssFeedUri != rssFeedTextBox.Text)
                applyButton.Enabled = true;
            else
                applyButton.Enabled = false;
            */
        }

        // [適用] ボタンが最後に押されてからの、すべての変更を適用します。
        private void ApplyChanges() {
            Properties.Settings.Default.videoClipPath = backgroundImageFolderTextBox.Lines;
            Properties.Settings.Default.Save();
        }

        private void btnOK_Click(object sender, EventArgs e) {
            try {
                ApplyChanges();
            } catch (ConfigurationException) {
                MessageBox.Show("設定を保存できませんでした。スクリーン セーバーと同じディレクトリ内に .config ファイルがあることを確認してください。", "設定を保存できませんでした。", MessageBoxButtons.OK, MessageBoxIcon.Error);
            } finally {
                Close();
            }
        }

        private void btnCancel_Click(object sender, EventArgs e) {
            Close();
        }

        private void btnApply_Click(object sender, EventArgs e) {
            ApplyChanges();
            applyButton.Enabled = false;
        }

        // ユーザー指定された URI が有効な RSS フィードにポイントするかどうかを確認します。
        private void validateButton_Click(object sender, EventArgs e) {
            try {
                // RssFeed.FromUri(rssFeedTextBox.Text);
            } catch {
                MessageBox.Show("有効な RSS フィードではありません。", "有効な RSS フィードではありません。", MessageBoxButtons.OK, MessageBoxIcon.Error);
                return;
            }

            MessageBox.Show("有効な RSS フィードです。", "有効な RSS フィードです。", MessageBoxButtons.OK, MessageBoxIcon.Exclamation);
        }

        private void browseButton_Click(object sender, EventArgs e) {
            // [ファイルを開く] ダイアログを開いて、イメージを選択します。

            DialogResult result = backgroundImageFolderBrowser.ShowDialog();
            if (result == DialogResult.OK) {
                backgroundImageFolderTextBox.Text = backgroundImageFolderBrowser.SelectedPath;
                UpdateApply();
            }
        }

        private void rssFeedTextBox_TextChanged(object sender, EventArgs e) {
            UpdateApply();
        }

        private void backgroundImageFolderTextBox_TextChanged(object sender, EventArgs e) {
            UpdateApply();
        }

        private void backgroundImageOpenFileDialog_FileOk(object sender, System.ComponentModel.CancelEventArgs e) {

        }

        private void backgroundImageFolderBrowser_HelpRequest(object sender, EventArgs e) {

        }

        private void button1_Click(object sender, EventArgs e) {
            DialogResult result = videClipOpenFileDialog.ShowDialog();
            if (result == DialogResult.OK) {
                backgroundImageFolderTextBox.Lines = videClipOpenFileDialog.FileNames;
                UpdateApply();
            }
        }

        private void rssGroupBox_Enter(object sender, EventArgs e) {

        }
    }
}

OptionsForm.cs は不要なコードを消してないので冗長。

C#でムービースクリーンセーバー
http://d.hatena.ne.jp/bellbind/20060428/1146200768
ムービースクリーンセーバーを作ったってはなしだけど、作るのに必要な情報は入って無いんで自分で調べて書いてみた。

  public SimpleScreenSaver() {
    this.FormBorderStyle = FormBorderStyle.None;
    this.WindowState = FormWindowState.Maximized;
    this.KeyDown += new KeyEventHandler(this.MyKeyDown);
    this.MouseDown += new MouseEventHandler(this.MyMouseDown);
    this.Load += new EventHandler(this.MyLoad);
    this.ClientSize = new Size(640, 480);
    this.player = new Video("movie.avi");
    this.player.Owner = this;
  }

(略)

cscでのビルドには/r:Microsoft.DirectX.AudioVideoPlayback.dllが必要だけど、これはc:\WINDOWS\Microsoft.NET\DirectX for Managed Code\*\以下にあるのでそれを使う。

私もとりえあず再生さえできれば良かったので AudioVideoPlayback を使いました。

あれ? もしかして DirectX の dll って最初からインストールされてたのかな? わざわざ SDK をダウンロードする必要ってなかった? まあ、スクリーンセーバーを作るためだけにわざわざ Visual Studio 2005 をインストールしてるわけだから、DirextX SDK を追加で入れるくらい誤差みたいなものということで。それにそもそも .NET Framework 2.0 をインストールする必要がある。スクリーンセーバーのためだけに .NET Framework 2.0 を要求するって結構すごいよなあ。

本当はもっといろいろ DirectX の機能を使ってみようかと思った。ビデオクリップの解像度にあわせてディスプレイの解像度を変更したり、マルチディスプレイ環境では再生するディスプレイを選択できるようにしたりとかね。でも、結局液晶ディスプレイで再生してるので、解像度を落としても dot-by-dot で再生できるわけじゃなく、スケーリングが入るので美しさは変わらない。高い解像度のままでも CPU や GPU の負荷もとくに問題にならなかった。マルチディスプレイ対応については、「あったらいいな」くらいで必須じゃない。というわけで今の私の環境ではあんまり意味がなくなったので見送った。

2006-04-27 (Thu)

* C# でスクリーンセーバーを作る

この記事の直リンクURL: Permlink | この記事が属するカテゴリ: [.net] [C#] [Windows]

Visual Studio 2005 Express Edition を使ってスクリーンセーバーを作る。

2006-04-25 で Visual Studio 2005 (VS2005) のインストールも終わった。VS2005 をインストールした理由の「作りたかったちょっとしたアプリケーション」とはスクリーンセーバーだ。2006-04-20 の「FF12 のムービーをリッピング (ripping) して再生」でリッピングした MPEG2 ムービーを再生するスクリーンセーバーを作りたい。そういうスクリーンセーバーはすでにいくつかあるが、やっぱり自分好みのものがほしい。

VS2005 に慣れるにはいい題材かな・・・と思ったら、そもそも VS2005 のプロジェクトテンプレートとして「スクリーンセーバースタートキット」というのがあるじゃん。これはラッキー。とりあえずこれを見てみよう。

スクリーンセーバースタートキット

このスタート キット プロジェクトでは、RSS フィードからのニュース記事を表示するスクリーン セーバーの構築方法を紹介します。

- スクリーンセーバースタートキット

スクリーンセーバーの実体は単なる実行ファイルと聞いたことがあったが、その通りだった。いくつかの引数を処理できる実行ファイルを作り、拡張子を exe から scr に変更して windows ディレクトリに配置すれば、「画面のプロパティ」などからスクリーンセーバーとして設定できる。

スクリーンセーバースタートキットには、そういった実行ファイルを作るために必要なもの一式が入っている。メインフォーム一つ、設定用のオプションフォーム一つ、エントリポイント (アプリケーションの開始点) の C# ソースファイルが一つ、あとはライブラリとリソース群。

以下はエントリポイント。Program.cs に書かれている。

static void Main(string[] args) {
    if (args.Length > 0) {
        // 2 文字のコマンド ライン引数を取得します。
        string arg = args[0].ToLower(CultureInfo.InvariantCulture).Trim().Substring(0, 2);
        switch (arg) {
            case "/c":
                // オプション ダイアログを表示します。
                ShowOptions();
                break;
            case "/p":
                // プレビューに対して何もしません。
                break;
            case "/s":
                // スクリーン セーバーのフォームを表示します。
                ShowScreenSaver();
                break;
            default:
                MessageBox.Show("コマンド ライン引数が無効です :" + arg, "コマンド ライン引数が無効です。", MessageBoxButtons.OK, MessageBoxIcon.Error);
                break;
        }
    } else {
        // 渡される引数がない場合、スクリーン セーバーを表示します。
        ShowScreenSaver();
    }
}

必ず必要な引数の処理などは全部テンプレートに入ってる。いやー楽だ。実際、ビルドしてすぐにスクリーンセーバーとして使える。動作を変えたければ、上記から呼んでいる ShowScreenSaver() にその処理を書けば OK。私の場合、動画を再生するコードを書けばいい。

- C# で動画を再生する

動画を再生するにはいろいろ方法はあると思うが、せっかくだからいままでやったことのない領域でやろうと思う。スクリーンセーバー部分はテンプレート使っちゃってるし。というわけで DirextX を使うことにした。再生するだけなら簡単だった。詳細はまた後ほど。

2006-04-25 (Tue)

* Visual Studio 2005 Express Edition をインストール

この記事の直リンクURL: Permlink | この記事が属するカテゴリ: [.net] [C#]

ちょっとしたアプリケーションを作るため、Visual Studio 2005 が必要になったのでインストール。インストールするマシンはこれで3台目。

- インストーラを使うので ISO イメージのダウンロードは必要なし

いつの間にか直接実行可能なインストーラが Web で公開されるようになっていた。2005-12-16 に書いた「Visual Studio 2005 Express Edition 日本語版ダウンロード」の時点では iso イメージしか公開されていなかったので、ダウンロードした後 CD-R などに焼くか、iso イメージから 仮想 CD-ROM ドライブを生成するツールなどを使う必要があって手間がかかったが、これでかなり楽になった。

Web から直接インストール可能な "Webインストール" の公開を開始いたしました。Visual Basic、Visual C#、Visual C++、Visual Web Developer 各ページの上部にある「Web からインストール」リンクをクリックいただくことで、インストールを開始いただけます。なお、追加の製品ドキュメントを参照する場合は、MSDN Express Library をインストールしてください。

以下の Visual C# 2005 Express Edition 日本語版 をダウンロード。
http://go.microsoft.com/fwlink/?LinkId=51411&clcid=0x411

- Visual Studio 2005 Express Edition をインストール

インストールするにはダウンロードしたファイルを実行するだけ。

インストールする製品 (省略可) を選択してください。
インストール オプション
Microsoft SQL Server 2005 Express Edition x86 (ダウンロード サイズ: 55 MB)
SQL Server Express は、アプリケーション データの読み取り、書き込み、および配置を容易にする Microsoft SQL Server のベーシック バージョンです。


インストールするフォルダ(&I):

C:\Program Files\Microsoft Visual Studio 8\

以下の製品をダウンロードしてインストールします:
  Microsoft .NET Framework 2.0  Microsoft .NET Framework 2.0 日 本 語 Language Pack  Visual C# 2005 Express Edition  Microsoft SQL Server 2005 Express Edition x86
ディスク領域の必要条件: C: 893 MB
ダウンロードサイズの合計: 111 MB
インストールを続行する前にインターネットに接続してください。

SQL Server 2005 などのオプションがあるけど、とりえあえず全部入りで。もっとも、今回はディスクが足りなかったので、ネットワークドライブ上にインストールした。ある意味富豪的だね。

あとは OK や「次へ」を連打していれば、必要なパッケージを勝手にダウンロードしてインストールしてくれる。

Visual C# 2005 Express Edition が正常にインストールされました。最新の Service Pack およびセキュリティ更新プログラムに関しては、Windows Update を参照してください。

これでインストール完了。

- ライセンスキーをもらう

インストールはこれで完了だが、継続的に使用するにはシリアルナンバーというかライセンスキーをもらう必要がある。

30 日以内にソフトウェアの登録を行ってください。

この製品を続けてお使いいただくために、今すぐ登録を行ってください。後からヘルプメニューの [製品の登録] を選択して、登録を行うこともできます。詳細については、登録の利点を参照してください。

以前は無償提供の期間が一年しかないと聞いたので、すぐに登録してライセンスキーをもらった。しかし今となってはもう「ずっと無償」になったわけだから、必要になったときで良いと思う。30日以上使い続けることがわかっていれば登録しても良いけど、今回はせいぜい1週間くらいしか使わないだろうしね。

ちなみに他のマシン用に発行されたライセンスキーを入れてみたけど見事に弾かれた。そりゃそうだよね。マシン固有の値からハッシュしてるだろうし。以前登録したときは MSN パスポートが必要だったりしたので、その手間を省けるならとやってみたけど、そうは問屋が卸しませんでしたとさ。

2006-03-03 (Fri)

* プログラミング C# 第4版を購入した

この記事の直リンクURL: Permlink | この記事が属するカテゴリ: [] [C#] [.net]

プログラミングC#―C#2.0/.NET2.0/Visual Studio2005対応プログラミングC#―C#2.0/.NET2.0/Visual Studio2005対応

ジェシー リバティ / Jesse Liberty / 鈴木 幸敏 / 首藤 一幸 / 情報技研
発売日: 2006/02


amazon で詳しく見る   bk1で詳しく見る

プログラミング C# 第4版を購入。ひとまず全22章中の3章まで読んだ。3章はまだ C# の基礎の部分だが、かなり勉強になる。曖昧な部分が消えていく感じ。「そうなんだ」と発見することもいくつかあり、すでにマーカーや書き込みが10カ所くらい入っている状態。

C と Delphi と JavaScript と Perl と PHP と Ruby と C# のそれぞれの文法や仕様が頭の中でごちゃごちゃになることがある。foreach の書き方とか、ループを途中で脱出するのは last なのか break なのかとか、switch case が使えるのはどれなのかとか、bool 型が使えるのはどれなのかとか、プロパティが使えるのはどれなのかとか。

こんな状況で今後 C# を仕事で使うことに不安を感じてた。とりあえずコードを書くことはできるけど、C# を使いこなせていないので冗長な書き方になったり、コードに曖昧な部分が残ったりしかねない。この本を読むことで、それを解決できそうだ。

言語の基礎を記述している章でさえ「勉強になる」と言ってる状態なんだから、より先の章は推して知るべし。早めに目を通しておこう。

2006-02-20 (Mon)

* ASP.NET で Trace が有効かどうか判定する

この記事の直リンクURL: Permlink | この記事が属するカテゴリ: [.net] [C#]

System.Web.HttpContext.Current.Trace.IsEnabled でトレース自体の有効・無効を判定できる。

- トレース自体が有効かどうかを判定する

ASP.NET にはトレース出力機能がある。prinf デバッグなどと違い、トレースの有効・無効を web.config 等の設定ファイルで一括変更できるため使い勝手がよい。

トレースがオフになっている場合はデータは画面などには出力されない。しかし、取得に時間がかかるデータなどの場合、出力だけでなくトレースに必要なデータのセットアップ自体をしないで欲しいときがある。

System.Web.HttpContext.Current.Trace.IsEnabled にトレース自体の有効・無効がセットされているので、これを判定して Trace を呼び分けてやればよい。

if (HttpContext.Current.Trace.IsEnabled) {
    Tarce.Warn(GetHeavyData());
}

もしくは、コンパイル時の条件変数を使う。ただ、当然ながら有効化にはコンパイルが必要で手間がかかる。 HttpContext.Current.Trace.IsEnabled の方が使い勝手が良い。

#if DEBUG
Tarce.Warn(GetHeavyData());
#endif

via: .NETエンタープライズWebアプリケーション開発技術大全 vol.3 ASP.NET応用 240ページ。

2006-02-10 (Fri)

* Visual Studio スタートページの既存のプロジェクトの表示件数を変える

この記事の直リンクURL: Permlink | この記事が属するカテゴリ: [.net] [C#]

Visual Studio スタートページには、作業したプロジェクトの履歴が表示される。過去のプロジェクトの環境をすぐに復元して作業を始められるので便利。ただ、デフォルトでは4件しか表示されない。これだと圧倒的に足りない。

プロジェクトのファイルはソースコード管理ツール VSS (Visual Source Safe) から取得しているし、その後のソースコード管理はソリューションエクスプローラに任せられるので、ローカルのどこに保存されたかなどはあまり気にしてない。

そのため、4件という履歴の保存件数を超えたプロジェクトを開こうとすると、プロジェクトのローカルのパスや名前を覚えていなければならないので時間がかかる。久しぶりに開くプロジェクトならなおさら。ブックマークしてるけど URL を知らないサイトを検索なしで探すような感じ。

「既存のプロジェクト」の表示件数を変えてもっと大量に表示したい。以下、Visual Studio .NET 2003 での設定方法。

- Visual Studio スタートページの既存のプロジェクトの表示件数を変える

「ツール (T)」 の「オプション (O)」 の「環境」ディレクトリの「全般」を開く。
以下を設定する。

最後に使用した一覧に表示する項目(&Y): 24 項目

99 を入れたら、以下のダイアログが出て拒否された。

Microsoft Development Environment

最後に使用した一覧には 1 - 24 項目まで含めることができます。

仕方ないので24で設定。ヘルプを読んだら以下のようにちゃんと書いてあった。

[最後に使用した一覧に表示する項目]

[ファイル] メニューに表示される、最近使ったプロジェクトとファイルの数をカスタマイズします。1 〜 24 の数値を入力します。既定は 4 です。このオプションを使用すると、最近使用したプロジェクトやファイルを簡単に表示できます。

99くらいは設定させてほしいな。こういうものは可能な限り保存しておくと後で便利だからね。2003-03-31 の「/etc/profile への設定内容」で書いたように、私はシェルのコマンドラインの履歴も10万件保存してる。あとでコマンドを再び使いたいときに非常に楽だ。ケータイの着信履歴もデフォルトで1000件くらい保存しておいてほしいと思う。見られたくないものがあるときは別だけど。

2006-02-02 (Thu)

* C# では文字列の比較に Equals を使うな

この記事の直リンクURL: Permlink | この記事が属するカテゴリ: [.net] [C#]

C# では文字列の比較に Equals を使わない方がいい。== を使った方がコンパイラの型チェックの恩恵を受けられるし、間違いを少なくすることができる。

Equals を使うな。使う事を推奨するな。
http://www.ailight.jp/blog/kazuk/archive/2006/01/31/11043.as ...
Equals はタイプセーフではない。このため、型のエラーの発見が遅れる。

例:

int a;
string b;
bool result = a.Equals( b );

int a;
string b;
bool result = (a==b);    // CS0019: 演算子 '==' を 'int' と 'string' 型のオペランドに適用することはできません。

よっぽどの理由が無い限り == で比較せよ。

Visual Studio 2003 環境で試してみた。int 型の 0 と string 型の 0 を比較する。

int i = 0;
string s = "0";

Console.WriteLine(i.ToString() == s);
Console.WriteLine(string.Equals(i.ToString(), s));
Console.WriteLine(string.Equals(i, s));
Console.WriteLine(s.Equals(i));

実行結果。上記コードを書いた「プログラマ」としては、比較結果はすべて True になって欲しいのだが、そうなっていない。

True
True
False
False

string.Equals() メソッドにはオーバーロードがあり、string 型同士を比較するものと、Object 型として比較するものがある。Object 型同士の比較だと int 型のオブジェクトと string 型でのオブジェクトという違いがあるので false になってしまう。

これ、バグの元だなあ。Perl だったら型変換があっても気にしないけど、C# というせっかく型の恩恵を受けられる言語を使ってるんだから、最大限に活用した方がいい。

Equals の方が速いとのことだが、上記の動きを理解した上で、100万回のループの中などの速度が重要な部分で使うならいい。でも、日常的に Equals を使うのは避けた方が間違いを減らせる。「速いらしいから」という理由で Equals を常用していた後輩は、上記の動きを知らなかった。

2006-01-26 (Thu)

* プログラミング C# 第4版

この記事の直リンクURL: Permlink | この記事が属するカテゴリ: [] [C#] [.net] [プログラミング]

オライリーのメールマガジンを読んでいたら、プログラミングC# 第4版刊行のお知らせが書かれていた。

プログラミングC#―C#2.0/.NET2.0/Visual Studio2005対応プログラミングC#―C#2.0/.NET2.0/Visual Studio2005対応

ジェシー リバティ / Jesse Liberty / 鈴木 幸敏 / 首藤 一幸 / 情報技研
発売日: 2006/02


amazon で詳しく見る   bk1で詳しく見る

Jesse Liberty著 鈴木 幸敏、首藤 一幸、株式会社情報技研 訳
5040円

2006年2月発売予定とのこと。まだ amazon に登録されてないようなのでリンクは張らない。「プログラミングC# 第3版」では開発運用編と言語詳解編として分冊になってたけど、第4版では一冊にまとまったのかな? 原書は644ページもあるし、そうなんだろうな。

そろそろリファレンスとして一冊手元に欲しいな。第3版は仕事場では何人か持っている人がいるのですぐに借りることはできるけど、メモを書き込んだり、マーカーを使ったりできないしね。C# 2.0 に対応してるなら買おう。

Programming C#Programming C#

Jesse Liberty
発売日: 2005/04


amazon で詳しく見る

ちなみに、原書ならば日本の amazon でもすぐに手に入る。

- Programming C# 4th Edition は C#2.0 と Visual Studio 2005 対応

うーん、原書は2005年2月なので C#2.0 は未対応な雰囲気・・・?

oreilly.com -- Online Catalog: Programming C#, Fourth Edition
http://www.oreilly.com/catalog/progcsharp4/
The fourth edition of Programming C#--the top-selling C# book on the market--has been updated to the C# ISO standard as well as changes to Microsoft's implementation of the language. It also provides notes and warnings on C# 1.1 and C# 2.0.

と思ったけど、上記解説によると C#2.0 向けの記述や警告があるとのこと。

amazon に掲載されている第4版の原書の表紙画像の右肩にも 4th Edition Covers C# 2.0, .NET 2.0 & Visual Studio 2005 と書かれてるし、それなら翻訳版も十中八九対応してるでしょう。

via: O'Reilly Japan News 第96号

2006-01-23 (Mon)

* C# の正規表現クラスに複数のオプションを指定する

この記事の直リンクURL: Permlink | この記事が属するカテゴリ: [C#] [.net] [Perl]

C# の正規表現クラスに複数のオプションを指定するには、 | で RegexOptions 列挙体の OR を取る。|| ではない。

- 今日の失敗 論理演算子 || を RegexOptions に使おうとした

文字列を強調処理する正規表現を書いていたところ、Regex クラスのコンストラクタに正規表現オプションとして RegexOptions 列挙体を渡すところでコンパイルエラーが出た。

Regex highLight = new Regex(Regex.Escape(keyword), RegexOptions.IgnoreCase || RegexOptions.Multiline);

C:\CSProjects\Prototype\ConsoleApplication1\ConsoleApplication1\Class1.cs(30): 演算子 '||' を 'System.Text.RegularExpressions.RegexOptions' と 'System.Text.RegularExpressions.RegexOptions' 型のオペランドに適用することはできません。

んん? なんでエラーになってるの? .NET というか C# で複数の正規表現オプションを Regex クラスのコンストラクタに渡したいときは、OR を取れば良いんでしょう? かなり前にやった覚えがあるんだけど・・・。

あ、わかった。ビット演算の OR (|) じゃなくて論理演算の OR (||) を使ってる。あはは。これが原因か。以下のように修正して無事コンパイルできた。

Regex highLight = new Regex(Regex.Escape(keyword), RegexOptions.IgnoreCase | RegexOptions.Multiline);

- RegexOptions 列挙体でよく使うもの

ちなみに System.Text.RegularExpressions.RegexOptions 列挙体でよく使うのは以下の3つかな。Perl でも i m s などとして指定してたよね。最初は m と s の違いを実感できなかった。とくに、同時に指定したらどうなるのかがわかりにくかったので、2003-03-25 の「Perl の正規表現のオプション m と s」では 実際にどう使うかをまとめた。

RegexOptions 列挙体 - System.Text.RegularExpressions
http://www.microsoft.com/japan/msdn/library/default.asp?url= ...
IgnoreCase
検索時に大文字と小文字を区別しないことを指定します。

Multiline
複数行モードを指定します。^ と $ の意味を変更して、文字列全体の先頭と末尾だけでなく、任意の行の先頭と末尾にもそれぞれが一致するようにします。

Singleline
単一行モードを指定します。\n 以外の任意の文字ではなく、すべての文字と一致するようにピリオド (.) の意味を変更します。

2005-12-16 (Fri)

* Visual Studio 2005 Express Edition 日本語版ダウンロード

この記事の直リンクURL: Permlink | この記事が属するカテゴリ: [.net] [C#]

とうとう Visual Studio 2005 の Express Edition 日本語版のダウンロードができるようになった。

公開されているのは iso イメージなので、インストールはちょっと面倒。Daemon Tools などの CD-ROM 仮想マウントツールがあると便利。

Visual C# 2005 Express Edition 日本語版
http://www.microsoft.com/japan/msdn/vstudio/express/vcsharp/
http://download.microsoft.com/download/9/5/7/9576E49E-1EDA-4 ...
md5: 58e69034c80218893d8e6973e763106c
sha1: db3d0f4d76e6603edd35e75038a5090ec1e25a71
crc32: ce838830

Visual Web Developer 2005 Express Edition 日本語版
http://www.microsoft.com/japan/msdn/vstudio/express/vwd/
http://download.microsoft.com/download/C/E/6/CE6B9F63-0E29-4 ...
crc32: df626aa6

とりあえず Visual C# 2005 Express Edition 日本語版をダウンロードした。Visual Web Developer 2005 Express Edition はしばらく使う機会はないと思う。趣味で ASP.NET のアプリケーションを作っても、公開できるサイトがないから。

- Visual C++ 2005 と Visual Basic 2005 はたぶん使わない

あとはメモだけ。たぶんこれも趣味で使うことはないだろう。

Visual C++ 2005 Express Edition 日本語版
http://www.microsoft.com/japan/msdn/vstudio/express/visualc/
http://download.microsoft.com/download/8/E/8/8E85D539-2255-4 ...
crc32: B3AD1A2F

Visual Basic 2005 Express Edition 日本語版
http://www.microsoft.com/japan/msdn/vstudio/express/vbasic/
http://download.microsoft.com/download/A/B/4/AB4DA3D7-CC3A-4 ...
md5: ef27f47cbcda6daea1473084f7536a3c
sha1: 344c585cb517679b5dd20cfca05bca560e454f41
crc32: 6ee067f9

Visual J# は英語版しかないので省略。

- .NET Framework 2.0 と SDK

.NET Framework 2.0 と SDK も必要なのかな? VS.NET 2003 インストールしたときはどうしてたっけ? とりあえず全部入れておくか。

Download details: .NET Framework Version 2.0 Redistributable Package (x86)
http://www.microsoft.com/downloads/details.aspx?FamilyId=085 ...
http://download.microsoft.com/download/5/6/7/567758a3-759e-4 ...

Microsoft .NET Framework 2.0 日本語 Language Pack (x86)
http://www.microsoft.com/downloads/details.aspx?FamilyID=39c ...
http://download.microsoft.com/download/5/9/4/594a8f51-ba02-4 ...

ダウンロードの詳細 : .NET Framework 2.0 SDK 日本語版 (x86)
http://www.microsoft.com/downloads/details.aspx?FamilyID=FE6 ...
http://download.microsoft.com/download/5/7/2/57246de2-5e4c-4 ...
md5: d41d8cd98f00b204e9800998ecf8427e
sha1: da39a3ee5e6b4b0d3255bfef95601890afd80709
crc32: 00000000

- とりあえずダウンロードだけ

とりあえずダウンロードだけした。インストールはまたあとで。

2005-12-08 (Thu)

* C# でべき乗 (累乗) を扱うには Math.Pow()

この記事の直リンクURL: Permlink | この記事が属するカテゴリ: [C#]

C# にはべき乗 (累乗) を扱うための演算子は存在しない。 ^ は論理演算子で、べき乗を計算する演算子ではない。
演算子は存在しないので、Math.Pow() を使う。

C# プログラマーズ リファレンス C# の演算子
http://www.microsoft.com/japan/msdn/library/default.asp?url= ...

Math.Pow メソッド
http://www.microsoft.com/japan/msdn/library/ja/cpref/html/fr ...
指定の数値を指定した値で累乗した値を返します

べき乗って 羃乗って書くんだ。ひらがなで書く方しか知らなかったよ。

2005-11-30 (Wed)

* C# の StringBuilder と += による文字列連結の速度比較

この記事の直リンクURL: Permlink | この記事が属するカテゴリ: [.net] [C#]

C# で文字列連結するとき、string 型を += で連結するとパフォーマンスが落ちるので、ある程度の回数以上の文字列連結には StringBuilder を使うということが常識となっている。string は不変なので、連結の度に新しいオブジェクトの生成と破棄がおこなわれるからというのが差の発生原因。

ただ、私は実際どの程度性能が劣化するのか計測したことがない。このままだとコードレビューの時に「StringBuilder 使え」と指摘をしても、その根拠となる数値を示せない。後輩などに「計測もしないで性能が落ちるなんて言ってるんですか? 性能を理由にコードを書き換えるときはまず計測しろって言ってたのは斎藤さんじゃないですか?」とか言われかねないので、計測してみる。幸いなことに、私の所にはこの程度の指摘をする必要のある後輩はいないので問題ないけど。

- 計測用コード

傾向がわかればいいので、コードは簡単に書いた。

using System;
using System.Text;

namespace ConsoleApplication1
{
    /// <summary>
    /// Class1 の概要の説明です。
    /// </summary>
    class Class1
    {
        /// <summary>
        /// 文字列連結の速度比較
        /// </summary>
        [STAThread]
        static void Main(string[] args) {

            int times = 100000;
            Console.WriteLine("{0:d} times loop.", times);

            DateTime start_str = DateTime.Now;
            string str = string.Empty;
            for (int i = 0; i < times; i++) {
                str += i.ToString();
            }
            Console.WriteLine("String += : " + (DateTime.Now - start_str).ToString());


            DateTime start_str_builder_default = DateTime.Now;
            System.Text.StringBuilder sb_default = new System.Text.StringBuilder();
            for (int i = 0; i < times; i++) {
                sb_default.Append(i);
            }
            Console.WriteLine("StringBuilder: " + (DateTime.Now - start_str_builder_default).ToString());
        }
    }
}

ちなみに実行環境は以下の通り。
富士通 FMV-E600 Celeron 1.7GHz 512MB Memory
Visual Studio 2003 C# のコンソールアプリケーションとして作成。
Debug モードでコンパイルし、CTRL + F5 で実行。

- 計測結果

計測した結果。times の数を変えて3パターン計測。

1000 times loop.
String += : 00:00:00.0156250
StringBuilder: 00:00:00

千回のループ。StringBuilder を使ったときの所要時間がゼロになってる。このタイマーの精度は 15ミリ秒単位で出力できる程度だっけ? その範囲内に収まっちゃったってことか。何にせよ1000回じゃ少ないなあ。

10000 times loop.
String += : 00:00:01.8125000
StringBuilder: 00:00:00.0156250

一万回のループ。百倍くらい違うな。実際にはいろいろ無茶をやった分に付随するコストも加算されるだろうから、環境によって差は変動するかもしれない。

100000 times loop.
String += : 00:05:20.5000000
StringBuilder: 00:00:00.0781250

十万回のループ。+= の方は耐えられないくらい遅い。指数的に処理時間が増大している。一方、StringBuilder は安定しているな。

これだけ差があれば、StringBuilder 使えという根拠は示せるね。使う基準としては、ループ内だったら迷わず StringBuilder。回数が固定的なループでも、設定の値や仕様が変わってループ回数が変わるのは良くあることだし。ループ外でも回数が多ければ StringBuilder。ループ外で、かつ一桁程度の回数しか連結しないんだったら += でもいい。

ところで、コンパイラは += を StringBuilder に置き換えるという最適化とかしてくれないのかな。この問題については、人間が適切な文字列連結手法を選ぶ方がスマートだと思うけど、コンパイラによる力業で解決できないのかな。

- StringBuilder のキャパシティの初期サイズによる速度の違い

StringBuilder は内部バッファを持っている。扱うデータのおおよそのサイズがあらかじめわかっているなら、そのバッファのキャパシティをコンストラクタに指定しておいた方が、バッファの拡張のオーバーヘッドを抑えられるので速くなるとのこと。これについても計測してみた。

計測に使ったコードは以下の通り。環境は変更なし。
バッファサイズは 1, 8, 64, 256, 1024, 8192, 16384, 65536, 16777216 を試すことにした。この数値の根拠は勘。ちなみに何も指定しない場合のデフォルトは 16 だそうだ。

using System;
using System.Text;

namespace ConsoleApplication1
{
    /// <summary>
    /// Class1 の概要の説明です。
    /// </summary>
    class Class1 {
        /// <summary>
        /// 文字列連結の速度比較
        /// </summary>
        [STAThread]
        static void Main(string[] args) {

            int times = 1000000;
            Console.WriteLine("{0:d} times loop.", times);

            DateTime start_str_builder_default = DateTime.Now;
            System.Text.StringBuilder sb_default = new System.Text.StringBuilder();
            for (int i = 0; i < times; i++) {
                sb_default.Append(i);
            }
            Console.WriteLine("StringBuilder: Capacity: Default: " + (DateTime.Now - start_str_builder_default).ToString());

            int[] capacity_list = {1, 8, 64, 256, 1024, 8192, 16384, 65536, 16777216};
            foreach (int capacity in capacity_list) {
                DateTime start_str_builder = DateTime.Now;
                System.Text.StringBuilder sb = new System.Text.StringBuilder(capacity);
                for (int i = 0; i < times; i++) {
                    sb.Append(i);
                }
                Console.WriteLine("StringBuilder: Capacity: " + capacity.ToString() + " : " + (DateTime.Now - start_str_builder).ToString());
            }
        }
    }
}

1000000 times loop.
StringBuilder: Capacity: Default: 00:00:00.8437500
StringBuilder: Capacity: 1 : 00:00:00.8281250
StringBuilder: Capacity: 8 : 00:00:00.8593750
StringBuilder: Capacity: 64 : 00:00:00.8281250
StringBuilder: Capacity: 256 : 00:00:00.8593750
StringBuilder: Capacity: 1024 : 00:00:00.9375000
StringBuilder: Capacity: 8192 : 00:00:00.8593750
StringBuilder: Capacity: 16384 : 00:00:00.8750000
StringBuilder: Capacity: 65536 : 00:00:00.8593750
StringBuilder: Capacity: 16777216 : 00:00:00.8125000

まずは百万回。うーん、あんまり変わらないね。ほんの少しだけ値が変動してるけど、百分の一秒レベル。F-ZERO でタイムアタックするなら大きな違いだけど、ここではそこまで重要な意味は持っていないと思う。誤差の範囲。

3000000 times loop.
StringBuilder: Capacity: Default: 00:00:02.7031250
StringBuilder: Capacity: 1 : 00:00:02.6562500
StringBuilder: Capacity: 8 : 00:00:02.7968750
StringBuilder: Capacity: 64 : 00:00:02.8437500
StringBuilder: Capacity: 256 : 00:00:02.9687500
StringBuilder: Capacity: 1024 : 00:00:02.8437500
StringBuilder: Capacity: 8192 : 00:00:02.9687500
StringBuilder: Capacity: 16384 : 00:00:02.8593750
StringBuilder: Capacity: 65536 : 00:00:02.9687500
StringBuilder: Capacity: 16777216 : 00:00:02.9062500

三百万回に増やしてもあまり変わらないね。本当はこのあと一千万回も試そうとしたんだけど、512MB のメモリしかない私のマシンではメモリを使い尽くしてスワップが発生し始めたので取りやめた。

キャパシティを指定した場合とそうでない場合で有意な差は見いだせなかった。もちろん、実行環境やデータのサイズによっても変動してくるとは思う。ただ、キャパシティの値はとりあえずデフォルトでも良いかなあ。とにかく += じゃなくて StringBuilder を使う方が大切ってことだな。極限までチューニングする必要があるときは、計測した上でどうするか決めれば良い。でも、そういう時ってたぶん StringBuilder 以外にボトルネックがありそうな気がする。

2005-11-22 (Tue)

* Visual Studio ユーザーグループ フォーラムの OPML

この記事の直リンクURL: Permlink | この記事が属するカテゴリ: [RSS] [.net] [C#]

先日、Visual Studio のユーザーグループ VSUG が発足した。

Visual Studio User Group > ホーム
http://vsug.jp/

vsug.jp にはユーザーが投稿できるフォーラムと呼ばれる掲示板があり、RSS も提供されている。しかし、それらを一気に RSS リーダーに登録する簡単な方法がない。RSS Auto Discovary もないし、OPML もない。

手軽に登録したいので OPML を作った。以下をファイル名 opml.xml などとして文字コード UTF-8 で保存し、OPML 対応の RSS リーダーに読ませればすべてのフォーラムを一気に購読できる。

<?xml version="1.0"?>
<opml version="1.1">
<head>
  <title>Planet .NET Japan</title>
  <dateCreated>Tue, 22 Nov 2005 15:18:02 +0000</dateCreated>
  <dateModified>Tue, 22 Nov 2005 15:18:02 +0000</dateModified>
  <ownerName>Saito Hiroaki</ownerName>
  <ownerEmail><img src="http://sonic64.com/img/mail.png" /></ownerEmail>
</head>

<body>
  <outline text="VSUG - .NET Framework" title="VSUG - .NET Framework" type="rss" xmlUrl="http://vsug.jp/Rss/GetRss.aspx?forumid=51&amp;nossl=x"/>
  <outline text="VSUG - Office 開発・VSTO" title="VSUG - Office 開発・VSTO" type="rss" xmlUrl="http://vsug.jp/Rss/GetRss.aspx?forumid=54&amp;nossl=x"/>
  <outline text="VSUG - VSUGからのお知らせ" title="VSUG - VSUGからのお知らせ" type="rss" xmlUrl="http://vsug.jp/Rss/GetRss.aspx?forumid=70&amp;nossl=x"/>
  <outline text="VSUG - Visual Basic" title="VSUG - Visual Basic" type="rss" xmlUrl="http://vsug.jp/Rss/GetRss.aspx?forumid=44&amp;nossl=x"/>
  <outline text="VSUG - Visual C#" title="VSUG - Visual C#" type="rss" xmlUrl="http://vsug.jp/Rss/GetRss.aspx?forumid=45&amp;nossl=x"/>
  <outline text="VSUG - Visual C++/CLI その他" title="VSUG - Visual C++/CLI その他" type="rss" xmlUrl="http://vsug.jp/Rss/GetRss.aspx?forumid=46&amp;nossl=x"/>
  <outline text="VSUG - Visual Studio 2005" title="VSUG - Visual Studio 2005" type="rss" xmlUrl="http://vsug.jp/Rss/GetRss.aspx?forumid=42&amp;nossl=x"/>
  <outline text="VSUG - Visual Studio 旧環境" title="VSUG - Visual Studio 旧環境" type="rss" xmlUrl="http://vsug.jp/Rss/GetRss.aspx?forumid=43&amp;nossl=x"/>
  <outline text="VSUG - Web アプリケーション" title="VSUG - Web アプリケーション" type="rss" xmlUrl="http://vsug.jp/Rss/GetRss.aspx?forumid=47&amp;nossl=x"/>
  <outline text="VSUG - Web ホスティングアプリケーション" title="VSUG - Web ホスティングアプリケーション" type="rss" xmlUrl="http://vsug.jp/Rss/GetRss.aspx?forumid=55&amp;nossl=x"/>
  <outline text="VSUG - データベース・データアクセス" title="VSUG - データベース・データアクセス" type="rss" xmlUrl="http://vsug.jp/Rss/GetRss.aspx?forumid=49&amp;nossl=x"/>
  <outline text="VSUG - マイグレーション・COM 相互運用" title="VSUG - マイグレーション・COM 相互運用" type="rss" xmlUrl="http://vsug.jp/Rss/GetRss.aspx?forumid=53&amp;nossl=x"/>
  <outline text="VSUG - モバイル・スマートクライアント" title="VSUG - モバイル・スマートクライアント" type="rss" xmlUrl="http://vsug.jp/Rss/GetRss.aspx?forumid=50&amp;nossl=x"/>
  <outline text="VSUG - ライティング・セキュアコード" title="VSUG - ライティング・セキュアコード" type="rss" xmlUrl="http://vsug.jp/Rss/GetRss.aspx?forumid=56&amp;nossl=x"/>
  <outline text="VSUG - リッチクライアント・UI コントロール" title="VSUG - リッチクライアント・UI コントロール" type="rss" xmlUrl="http://vsug.jp/Rss/GetRss.aspx?forumid=48&amp;nossl=x"/>
  <outline text="VSUG - 談話室" title="VSUG - 談話室" type="rss" xmlUrl="http://vsug.jp/Rss/GetRss.aspx?forumid=58&amp;nossl=x"/>
  <outline text="VSUG - 運用管理" title="VSUG - 運用管理" type="rss" xmlUrl="http://vsug.jp/Rss/GetRss.aspx?forumid=57&amp;nossl=x"/>
  <outline text="VSUG - 開発プロセス" title="VSUG - 開発プロセス" type="rss" xmlUrl="http://vsug.jp/Rss/GetRss.aspx?forumid=52&amp;nossl=x"/>
</body>
</opml>

VSUG に投稿しておいた。

Visual Studio User Group > フォーラム > VSUG フォーラム RSS の OPML を作りました
http://vsug.jp/tabid/63/forumid/58/postid/479/view/topic/Def ...

2005-11-07 (Mon)

* MCP 70-316 受験レポート 友人編

この記事の直リンクURL: Permlink | この記事が属するカテゴリ: [MCP] [.net] [C#]

友達が MCP 70-316 を受験して合格したとのこと。で、受験レポートを寄稿してくれた。載せていい? と聞いたら OK をくれたので、ここに掲載しておく。

友人はメインの開発環境として VS.NET を使っていないとのこと。合格できたのは、繰り返し復習したおかげなんだろうな。iStudy の 70-316 の出来が良くないというのは同意。ちなみに、友人と私はそもそも職場が異なるし、具体的に何を開発しているかはお互い知らない。とても忙しいプロジェクトに参加しているようだ。

■受験時点でのC#経験
以前、C# で開発中のプロジェクトに 5 ヶ月間、ヘルパーとしてプログラミングを
担当する機会があった。
ちなみに本来所属するプロジェクトでは、VS.NET 及び C# は採用していない。
Windows Form の入力画面と、画面で扱うデータを XML Web Service で取得・更新すると
いう、基本的かつ低めのレベルのモジュールを担当していた。

私がこのプロジェクトに参加した時点では、ベースとなるフレームワークが完成済であっ
たため、MCP で問われるような細かい設定等を担当する機会はなかった。
また、言い訳になるがヘルプ要請が急で、業務の時間的制約もあり、深い部分まで理解を
広げることはなかった。

というわけで、私は C# については、初心者に毛を生やした程度のレベルと思われる。
そういうレベルの方の参考になれば幸いである。

■受験勉強
勤務先で、講師を招いての研修会が開催されたので、利用することにした。
研修はカテゴリごとにテキストの解説と iStudy の演習を行うスタイル。
試験合格のみを目的としており、ポイントが明確で得意分野・苦手分野がはっきり掴め
るので、良い研修だと感じた。

ただ、基本的なプロパティや文法などは知っている前提での研修である。
C# での開発経験が全く無いか、非常に浅い方には苦しい研修になる可能性がある。
そういう方は、テキストが事前に配布されるので予め目を通しておくと良いだろう。

毎日の研修後、その日の範囲のテキスト精読と iStudy で復習を行った。
なお、iStudy の品質は劣悪で、設問ミス・回答解説の誤りや不足が多い。
責任問題に発展するのではないかという品質である。

研修では誤っている問題の訂正と丁寧な解説が行われるため、聞き漏らさず、正解選択
肢はもちろん、不正解選択肢についても、本来の使用目的や効果まで把握しておきたい。
ただし、選択肢の中にはそんなプロパティは存在しない、等のでっち上げ選択肢もある。
研修期間終了後は、受験までの1週間、帰宅後に iStudy 模擬試験とテキストの精読を
行った。iStudy 模擬試験では、93 〜 98 % の正答率だった。

■試験会場
R-PROMETRIC 社で申し込み、受験した。

■試験内容
出題は 42 問。
他の方の話を伺うと 50 問以上出題されたという話も聞いた。難易度などを組み合わせて
出題されるのだろうが、詳細は分からない。

私に出題された問題の内訳は、iStudy の内容とほぼ同じか、研修や iStudy で得た知識が
ストレートに問われた問題が約 5 割、その知識を基に思考すれば解ける問題が約 3 割、
残りは回答に必要な知識が不足していると感じる問題であった。

http://sonic64.com/2005-08-28.html の 70-315 のレポートでは、
iStudy をしっかりマスターすれば合格は確実、との内容だが、70-316 はそうではないと感じた。
C# の経験が浅い方は、iStudy や研修テキストの他、実際にコーディングしてみたり、
ヘルプを精読するなど、+αの努力が必要と思われる。

■時間配分
試験時間は 160 分。
1 問目から順に進め、少しでも正解かどうか怪しい問題にはマークを付けて進める。
即答できる問題もあれば、10 分ほど考えた問題もある。勉強不足を痛感した。
全部の問題を一巡した時点で、68 分経過とスローペースであった。

この間、一緒に受験した友人が 60 分ほどで退室。モニターに反射して映る友人の顔には、
晴れやかな余裕の表情が浮かぶ。たぶん合格したのだろう。
少し焦る。
一巡後、マークを付けた問題は 19 問。これらが全て不正解だと、間違いなく不合格だ。
更に焦る。

窓越しに秋雨模様の市街を眺め、気持ちを落ち着けて二巡目へ。
マークを付けていない問題は回答の選択ミスが無いかを確認し、マークを付けた問題は慎
重に再検討した。
二巡目では、回答修正が 2 問、選択ミス発見が 1 問あった。
試験のフォームは、コンポーネントのコントロール領域が広く、不用意なクリックで意図
しない選択肢にチェックが付いてしまうため、必ず見直すようにしたい。
また、マークを付けた問題のうち 7 問は回答に自信を持つことができた。
その結果、マークを付けた問題が 12 問となる。

これらが全て不正解だと、配点によっては不合格の危険性が残る。
だが、うち 6 問は正解候補を二択にまで絞り込めていて数問の正解が見込まれることと、
再度検討しても回答は変わらないと思われることから、終了することにした。
この時点で 103 分経過。

祈る気持ちでテスト終了ボタンをクリックした。
テスト結果を印刷中とのメッセージが 1 分ほど表示された。
緊張感と脱力感、期待と不安が入り交じった、嫌な時間が長く感じられた。
結果は 760 点。薄氷の合格だった。
もっと勉強と経験が必要だ。

合格おめでとう。

2005-10-11 (Tue)

* Reflector for .NET の逆コンパイルでアセンブリのソースを見る

この記事の直リンクURL: Permlink | この記事が属するカテゴリ: [.net] [C#]

Reflector (リフレクター) for .NET を使うと、.NET のアセンブリを逆コンパイルできる。

- Reflector for .NET とは

C# で書かれたコンパイル済みの .NET バイナリや DLL を Reflector でブラウズすると、C# や VB.NET のソースコードとして表示してくれる。.NET のマネージ土コードも逆コンパイルとか逆アセンブルなどと呼ぶのが正しいかわからないけど、その類のもの。いわゆるリバースエンジニアリングのためのツールだ。

Lutz Roeder's Programming.NET C# VB CLR WinFX
http://www.aisto.com/roeder/dotnet/

- Reflector for .NET の使い方

Reflector はインストール方法も使い方も超簡単。 http://www.aisto.com/roeder/dotnet/Download.aspx?File=Reflec ... から zip アーカイブを取得して展開するだけ。現時点の最新バージョンは Version 4.1.85.0 だ。

初回起動時には、どのアセンブリセットをロードするかを選択する。選択すると名前空間ごとにツリーが表示され、その中にある DLL を選んで右クリックし Disassembler を選択すれば、右側に逆アセンブルした結果が表示される。

ブラウズしたいアセンブリの追加も超簡単。左側の名前空間ツリーに DLL をドロップすると、ツリーにその DLL が持つ名前空間が追加されてブラウズできるようになる。

プルダウンメニューを使って、逆アセンブル後の言語を IL、C#、VB.NET、Delphi から選択することもできる。この機能を使えば各言語を相互に変換することもできそうだ。たとえば、VB.NET のソースを C# に変換したりするなど。必要ないのでやらないけど。

- Reflector を使うときはライセンスや著作権に注意

MS のコンサルティングファームの人は、このツールを紹介するときに「Reflector を使って MS の提供している DLL をリバースエンジニアリングすると、ライセンス違反になる可能性がありますよ」と言っていた。でも「便利なツール」とも言っていた。微妙な立場のようだ。

.NET Framework 1.1 の HTTP リクエストクラスである System.Net.HttpWebRequest はドメイン属性が指定されている Cookie を取り扱うことができないというバグを Reflector を使って見つけた話もあることだし、有用なツールであるのは間違いない。ライセンスに注意して使おう。

- Reflector のスペルが覚えられない

2003-07-29 の 「SQL の COALESCE」ほどではないが、Reflector というスペルも覚えにくい。日本人にとって鬼門の R と L の区別の問題があるからだ。Refrector とか Refrecter とか Reflecter などとよく間違えてしまう。正直、このメモにもスペルの間違いがあるんじゃないかと心配になるくらいだ。

2005-10-10 (Mon)

* MCP 70-316 を受験して合格した

この記事の直リンクURL: Permlink | この記事が属するカテゴリ: [MCP] [.net] [C#]

MCP 70-316を受験して合格した。以下、2005-08-28 の「MCP 70-315 を受験して合格した」と同じようにメモしておく。

- MCP 70-316

MCP 70-316の正式名称は Developing and Implementing Windows-based Applications with Microsoft Visual C# .NET and Microsoft Visual Studio .NET だ。要するに Visual Studio .NET 環境で C# を使って Windows アプリケーションを開発する開発者向けの試験。前回受験した MCP 70-315 は 70-316 の Web 版みたいな位置づけ。

- 私が受験した MCP 70-316 試験の詳細

MCP 70-316 Developing and Implementing Windows-based Applications with Microsoft Visual C# .NET and Microsoft Visual Studio .NET

試験番号 70-316
試験開催団体 アール・プロメトリック社
受験地 JP241/宇都宮
問題数 43問 (42問だったかも)
試験時間 160分
配点 1000点
合格点 700点
私の得点 1000点

- MCP 70-316 を受験するための学習

MCP 70-316 の受験のために、どのような学習をしたかを列挙。

3日間の研修を受けた。70-315 の時と同じ。
休憩込みで一日8時間弱、3日でカリキュラムが終わるという研修のスタイルも 70-315 と同じ。ポイントを列挙したテキストが用意され、講師がそれを説明。その後すぐさま iSutdy による問題演習と解説というスタイル。ただ、どうも今回は iStudy の点数がふるわない。iStudy 正答率は 50%から 100%の間だったと思う。研修終了時の模擬試験では満点を取れたが、これで本当に大丈夫か不安が残った。

iStudy for MCSD (.NET) CHOICEiStudy for MCSD (.NET) CHOICE

システム・テクノロジー・アイ
発売日: 2003/06/04
Windows

amazon で詳しく見る

iStudy による問題演習。
iStudy については 2005-08-23 の iStudy for MCSD インストールメモを参照。
iStudy の 70-316 の問題は設問や解説の不備、悪問が多い。これらは今後のアップデートで解消されていくだろうが、現時点ではあまりおすすめできる教材ではない。iStudy だけで合格できるかと聞かれたら、私は肯定する返事はしない。

MSDN のドキュメント読み込み。研修で配布されたテキストには、当該テーマの MSDN へのポインタが示されていたので、それを読んでおいた。細かいプロパティや仕様の説明があるので、読んでおくと良い。

あと、70-316 は 70-315 とテーマ的には重複している部分が非常に多いので、すでに 70-315 に合格していればかなり学習時間を節約できると思う。ただ、同じようなテーマなので、学習中はかなり油断と慢心が沸き起こってくる。70-315 でやったから大丈夫などと油断していると大怪我をするかもしれない。

- MCP70-316 で出題された問題の傾向と対策

はっきり言って覚えてない。全体的に 70-315 とテーマが重複している印象が強かった。iStudy で触れられていなかった、細かいプロパティの名前などが出ることもあった。あまり苦手な問題が出題されなかったことと、答えを絞りきれなかった問題が運良く正解になっていたせいもあってか、結果としては満点だった。

- MCP 70-316 受験時の時間配分

試験時間は160分。今回も時間が余った。合格圏内にいる人なら時間は多かれ少なかれ余ると思う。万全を期するために何度も見直しや検討をすれば時間は無くなるだろうが、早ければ30分から90分くらいで終わる。私の所要時間は1時間ちょっとくらいだったかな。一緒に受験した友達は1時間40分くらいだった。

- MCP 70-316 宇都宮試験会場および試験システムについて

70-315 の時と同じく、アール・プロメトリック社の宇都宮試験会場で受験。試験会場である TBC 学院ビルや試験申し込みについては 2005-08-22 の MCP 70-315 宇都宮会場の試験申し込みを参照。

TBC学院ビルへのアクセス。今回も友達に車で送迎してもらった。前回は友達に送迎のお礼として鳩サブレを一枚あげたが、今回は友達の希望の品の蜂蜜をあげた。その友達は前から蜂蜜をほしがっていたのだが、経済的な問題で蜂蜜を買えなかったとのこと。ちなみに、贈った蜂蜜はクローバーの蜂蜜。幼稚園の頃に野生のクローバーの蜜を味わったことがある。蜜の甘い香りが好きだったなあ。クローバーの蜂蜜も同じような味がするのかな?

試験開始時、アンケートに答えるといきなり「成績表を印刷しています」というメッセージが出る。間違った操作をしてしまい、試験が終わってしまったのかと一瞬焦ったが、そういえば前回も同じ文言が出たような記憶がある。メッセージが出てから少しすれば試験が始まるので心配ない。

今回は試験マシンのトラブルはなかった。前回は試験終了時に「成績表を印刷しています」のメッセージのままフリーズするというトラブルに見舞われたが、今回はとくに問題なく、快適そのものだった。おかげで、試験終了時に合否をすぐに確認することもできた。前回は自分の試験マシンでは合否がわからず、係員のいる事務室に行って成績表をもらって初めて合否がわかったので、それまでドキドキ感を味わう羽目になったが、今回は順調だった。

2005-09-13 (Tue)

* C# での変数名などの大文字小文字の使用スタイル

この記事の直リンクURL: Permlink | この記事が属するカテゴリ: [.net] [C#]

今回参加しているプロジェクトで、私が従うべき表記スタイルのメモ。言語は C# がメイン。コーディング標準の一部。HTML Table から引用したので見づらいかも。

ローカル変数名も camel なのか。アンダースコア _ でつなげる方に慣れてたのでちょっと違和感があるが、すぐに慣れるだろう。こういうのはプロジェクト内で統一していることが重要。

大文字小文字の使用スタイル

識別対象 形式 例

名前空間 Pascal System.Drawing
クラス Pascal AppDomain
インターフェイス Pascal IDisposable
列挙型 Pascal ErrorLevel
列挙値 Pascal FatalError
メソッド Pascal ToString
イベント Pascal ValueChange
プロパティ Pascal BackColor
読み取り専用の静的フィールド Pascal RedValue
フィールド変数 _Camel  _redValue
パラメータ(引数) Camel  typeName
局所変数 Camel  redValue
例外クラス Pascal WebException
定数 大文字形式 MAX_VALUE

例外    VS.NET の IDEが自動作成する識別子(メソッド等)については、この規約に従う必要はありません。

識別子における大文字の使用方法として、次の 3 つの形式があります。

Pascal 形式
識別子の最初の文字と、後に続いて連結されている各単語の最初の文字を大文字にします。Pascal 形式は、通常3 文字以上から構成される識別子に対して使用します。次に例を示します。

  BackColor

Camel 形式
識別子の最初の文字は小文字にし、後に続いて連結されている各単語の最初の文字を大文字にします。次に例を示します。

  backColor

大文字形式
識別子のすべての文字を大文字にします。次に例を示します。

  System.IO
  System.Web.UI

大文字形式って、System や Web が大文字になっていないけど、いいのかな? 例が適切じゃないだけか。READ_BUF_SIZE みたいなのが例として適切なのでは?

2005-08-30 (Tue)

* C# の StringCollection と string の配列の変換

この記事の直リンクURL: Permlink | この記事が属するカテゴリ: [.net] [C#]

System.Collections.Specialized には StringCollection という string のコレクションを楽に扱えるクラスが用意されている。StringCollection.AddRange() と StringCollection.CopyTo() を使うと、配列と StringCollection の間でデータをやりとりできる。

StringColletion を知る前は、ArrayList を使ったりしてた。キャストの手間が煩わしいとか言ってたような気がする。知らないって怖いなあ。

- String[] から StringCollection に値を渡す

String[] から StringCollection に値を渡すには、StringCollection.AddRange() メソッドを使う。

string[] stringArray = new string[0];
StringCollection sc = new StringCollection();
sc.AddRange(stringArray);

- StringCollection の値を配列に渡す

StringCollection の値を配列に渡すには、StringCollection.CopyTo() メソッドを使う。

StringCollection sc = new StringCollection();
string[] stringArray = new string[sc.Count];
sc.CopyTo(stringArray, 0);

StringCollection.CopyTo() メソッドの存在を知らずに以下のようなコードを書いてしまい、コンパイラに「型 'System.Collections.Specialized.StringCollection' を型 'System.Collections.ArrayList' に変換できません。」というエラーを出力されたことは秘密だ。

// コンパイルエラーになる
string[] stringArray = ((ArrayList)sc).ToArray(typeof(string));

というか、なんで ToArray メソッドが無いんだよー。CopyTo メソッドは開始位置インデックスを指定できるなど高機能であることはわかるけど、低機能でも上位のクラスと同じインターフェイスがあると迷わなくて済むのに。

2005-08-28 (Sun)

* MCP 70-315 を受験して合格した

この記事の直リンクURL: Permlink | この記事が属するカテゴリ: [MCP] [.net] [C#]

MCP 70-315 を受験し、無事合格した。いくつか書いておこうと思う。

- 私が受験した MCP 70-315 試験の詳細

MCP 70-315 Developing and Implementing Web Applications with Microsoft Visual C# .NET and Microsoft VisualStudio .NET

試験番号 70-315
受験日 2005年8月27日
試験開催団体 アール・プロメトリック社
受験地 JP241/宇都宮
問題数 43問
試験時間 130分
配点 1000点
合格点 700点
私の得点 829点

- MCP 70-315 を受験するための学習

MCP 70-315 の受験のために、どのような学習をしたかを列挙。

3日間の研修を受けた。
休憩込みで一日8時間弱、3日でカリキュラムが終わるという研修。ポイントを列挙したテキストが用意され、講師がそれを説明。その後すぐさま iSutdy による問題演習と解説というスタイル。この時点での iStudy 正答率は、テーマにもよるが60%から100%で推移していた。全体を通しての正答率の平均は75%くらいかなあ?

iStudy for MCSD (.NET) CHOICEiStudy for MCSD (.NET) CHOICE

システム・テクノロジー・アイ
発売日: 2003/06/04
Windows

amazon で詳しく見る

iStudy による問題演習。
iStudy については 2005-08-23 の iStudy for MCSD インストールメモを参照。
研修の復習という位置づけで、自主的にやった。この時点での正答率、つまり iStudy 2回目の正答率は 80% から 100%くらいだろうか。この時点では iStudy の答えを覚えてしまっていて、問題文を読まなくても正解できる状態になっているはず。でも、それでは勉強にならないので問題文をしっかり読み、少しでも理解が怪しいと思われる問題については iStudy の解説を熟読した。

事前にやったのは、主にこの2つ。あとはテキストを読んだりしていた。合計学習時間は、34時間くらい。内訳は、研修が 8 * 3 で24時間、復習が 2 + 2 + 3 + 3 = 10 時間位だろうか? 復習については良く覚えてないな。月曜日に試験対策の研修が始まり、土曜日に受験というスケジュールだったため、あまり復習している時間がとれなかった。要領のいい人や熟練した ASP.NET の開発者なら、もっと復習の時間が少なくても大丈夫だとは思う。

- 出題された問題の傾向と対策

70-315 は ASP.NET を使った開発をするための知識を問う試験。そのため、ASP.NET で使うクラスや設定ファイル、Visual Studio .NET の使い方、IIS の設定のしかた、SQL の知識などが問われる。普段あまり使わない多言語対応システム、すなわち Internationalization (i18n) や Localization (L10N) の構成方法なども出題される。全体として、とにかくどういう仕組みなのか概要を覚えることが大切。その後、細かい設定ファイルやプロパティを覚えると良いだろう。

本試験では全体的に iStudy で解いた問題と同じ趣旨の問題が出た。iStudy で 90% 以上正解できる力があれば、十分合格を狙えるだろう。さすがにまったく同じ問題というのは無かった気がする。70-315 の iStudy は問題数が 181問しかないので、真面目にこなすとすぐに答えを覚えてしまう。問題文を読まなくても正解できるようになるが、それではダメ。正解の根拠を理解していないと、実際の試験では設問に対応しきれない場合がある。

ただ、異常に難易度の低い問題も出題される。常識で考えれば解ける問題も出た。データバインドのやり方とかね。あと、SQL の知識さえあれば解ける問題もあった。INNER JOIN ができれば解けるという、いわばボーナス問題。

- MCP 70-315 受験時の時間配分

試験の時間について。試験は130分あるが、私は80分くらいで終了とした。以下、時間配分の内訳。

出題数が43問しかなかったので、一通りざっと解くだけなら50分くらいで終わる。その後保留にした問題を含め、もう一度全問についてじっくり問題文を読み、見直しをした。普通ここまですれば正答率95%くらいは行きそうなものだが、私の得点は829点と振るわなかった。単純に勉強不足な気もする。

要するに、合格レベルにいる人なら時間は必ず余る。なので、ゆっくり落ち着いて問題を解くのが吉と出ている。そういえば、友達は60分で終わったらしい。

- MCP 70-315 の宇都宮試験会場および試験システムについて

アール・プロメトリック社の宇都宮試験会場で受験。試験会場である TBC 学院ビルや試験申し込みについては 2005-08-22 の MCP 70-315 宇都宮会場の試験申し込みを参照。

TBC学院ビルへのアクセス。私は友達に車で送迎してもらったので、駐車場などは全く気にしなかった。友達には送迎のお礼として鳩サブレを一枚あげた。

TBC 宇都宮ビルは土足禁止。南大通りに面した正面玄関から入り、そのまま進むと左手にエレベータがある。エレベータの目の前に来客用下駄箱があり、そこで備え付けのスリッパに履き替えるシステム。私は気づかずにそのままエレベータに乗ろうとしてしまったが、エレベータの壁に土足厳禁という趣旨の張り紙があったので気づくことができた。

試験申込書に書かれた集合時間まで20分くらい余裕があったので、6F エレベータ前でテキストを確認していたが、先に受付を済ませても良かったのかもしれない。

受付をすませると、「受験セット」というクリアケースを渡される。メモ用のボードとペン、受験の諸注意を印刷した紙、ロッカーの鍵が入っている。受験会場にはこの受験セット以外は一切持ち込み禁止で、受験前にすべてロッカーに収めるように指示される。携帯電話は言うに及ばず、財布や腕時計さえ持ち込み禁止だった。普段は腕時計をしない私だが、何か試験を受ける時は念のため時計をしていく。今回は G-SHOCK を身につけていったが、全く無駄だった。

そうそう、私の隣の受付には、仕事場の先輩が来ていた。受付を終えるまで気づかなくて、挨拶できなかったけど。いつもスーツの先輩が私服を身にまとっていたので、気づくのが遅てしまった。

試験を受ける部屋は10畳くらいの広さだったろうか。そこに ATM についているような仕切りで区切られた席が並ぶ。席の数は数えてないが、6か7席だったと思う。

試験を受ける際のマシンは DELL の PC。ディスプレイは IBM製の 17インチ CRT。リフレッシュレートが 60Hz くらいで見づらい。

受験中に雷都宇都宮名物の夕立が発生。停電するんじゃないかとハラハラさせられた。試験マシンに UPS (無停電電源装置) が付いていたかどうかは不明。幸いにして停電はおこらなかった。

試験マシンにはトラブルが多いようだ。7人中3人ぐらいがマシンや試験システムのトラブルに見舞われていた。「次の問題に移動するボタンを押したら、いきなり試験が終了したんですが」とか、「動かなくなっちゃったんですが」 という声が聞こえてきた。私自身も、試験終了ボタンを押したら、「成績表を印刷中」のまま試験プログラムが反応しなくなった。仕方がないので手元の試験官呼び出しスイッチで試験官を呼んで対処してもらった。

試験が終わると結果を印刷した紙をもらえる。本当は試験終了ボタンを押すとすぐさま合否がわかるそうだが、試験プログラムが固まってしまったので、結果がわかったのはこのときになってからだった。

2005-08-22 (Mon)

* MCP 70-315 宇都宮会場の試験申し込み

この記事の直リンクURL: Permlink | この記事が属するカテゴリ: [MCP] [.net] [C#]

いろんな事情があって MCP を取得する必要が出てきて、MCP 70-315 を受験する手続きをした。

MCP 70-315 の正式名称は、MCP 70-315 Developing and Implementing Web Applications with Microsoft Visual C# .NET and Microsoft VisualStudio .NET だ。長い。要するに C# と ASP.NET の試験。

無料でリトライできるキャンペーンをやってるので利用した。
サポート 1: 一回目不合格でも二回目の受験料無料
http://www.microsoft.com/japan/learning/mcp/offers/Support1. ...

MSN Passport のアカウントを取ったりいろいろ手間がかかったけど、保険料だと思えば許せる。何しろ一回受験するだけで15000円かかるからなあ。万が一不合格になったときは非常に痛いし。

- 宇都宮で MCP 試験を開催している団体と試験会場

MCP 試験は複数の試験実施団体で受験できる。今回はプロメトリックを選んだ。ピアソンでもいいんだけど、検索したらアール・プロメトリック社が先に表示されたのでプロメトリック社で受けることにした。

プロメトリック R-PROMETRIC
http://www.prometric-jp.com/

ピアソン VUE
http://www.vue.com/japan/

プロメトリック社にアカウントを登録し、Prometric Identification Number をもらった。2005年8月27日 宇都宮会場を予約。会場となってる建物はどこにあるの? あー、あの強制左折レーンのあるあたりか。

プロメトリック社 宇都宮試験会場 TBC ビル 栃木県宇都宮市南大通り2丁目1-2
http://maps.google.co.jp/maps?q=%E5%AE%87%E9%83%BD%E5%AE%AE% ...

ピアソンは宇都宮市内に二つ会場がある模様。ページの一番下にそれぞれの会場の説明がある。
http://www.vue.com/japan/TestcentersList/Kanto.html
http://www.vue.com/japan/TestcentersList/Map/showmap.html?.. ...
http://www.vue.com/japan/TestcentersList/Map/showmap.html?.. ...

- 試験会場の予約状況確認

プロメトリックの試験会場の空席状況は以下で確認できる。

プロメトリック社 予約状況確認ページ
http://www3.prometric-jp.com/reserve/center_map.asp?conditio ...
試験会場と日付を選ぶと、空席状況を確認できる。空席状況は一コマ単位なので注意。以下の注意書きの通り。

※空席表示の場合でも、希望する試験の所要時間によっては、予約が出来ない場合がございます。
例)135分の試験の場合は連続3枠分の空席が必要となります。

ピアソンは予約状況などを確認する方法がよくわからない。アカウント作る必要があるのかな? 手間かかるなあ。そういう情報を簡単に参照できないのは不便だなあ。プロメトリックはウェブから予約状況を確認できるのにね。

- チュートリアルを受験

試験システムを事前に理解しておくために、チュートリアルをダウンロードできる。地理を扱った10分程度の簡単な試験で、60%で合格。で、やってみたらなんと不合格になってしまった。途中で電話をかけてたら、いつの間にか時間切れになっちゃっただけなんだけど。チュートリアルで不合格になるなんて、なんか行き先不安な感じだ。本試験大丈夫なのかなー。

2005-08-16 (Tue)

* C# でファイルを暗号化・復号化する

この記事の直リンクURL: Permlink | この記事が属するカテゴリ: [.net] [C#]

MSDN を参考に C# で AES (Rijndeal) を使って暗号化・復号化するサンプルを書いた。

MSDN Online = 10 行シリーズ 〜 10 行でズバリ !! 暗号化 (C#) 〜
http://www.microsoft.com/japan/msdn/thisweek/10lines/encrypt ...

- .net には標準で AES などの暗号化ライブラリが用意されている

.net には標準で暗号化ライブラリが入ってるので、System.Security.Cryptography にあるクラスを使えば速攻で暗号化・復号化できる。とても楽だ。

RijndaelManaged メンバ
http://www.microsoft.com/japan/msdn/library/default.asp?url= ...


MSDN サンプルでは 3DES を使っていたが、私のサンプルコードでは AES を使った。3DES は遅いだろうから。結城さんの「暗号技術入門」にも以下のように書かれていたし。「今後使うなら、AES (Rijndeal) がよいでしょう。安全で高速、しかも幅広いプラットホームで利用できるからです。」

「暗号技術入門」は良い本だ。非常にわかりやすい。認証や暗号化の機能をシステムに組み込む必要があるけど、知識がないというエンジニアは必読。この本を読んだおかげで、IV (Initialization Vector - 初期化ベクタ) やブロック暗号モードの意味を知ることができた。

ただ、知ってるのとライブラリを使いこなせるというのは別の概念だ。事実、最初にライブラリのヘルプだけを見て書こうとしたら以下のようなエラーを出された。しょうがないので MSDN のサンプルを見たという次第。

System.Security.Cryptography.CryptographicException : 指定された Initialization Vector (IV) のサイズは、このアルゴリズムのブロック サイズと一致しません。

無理に自分で生成せずに、普通に RijndaelManaged.GenerateIV() メソッドを使えば良いのね。

- C# で AES を使って暗号化・復号化するサンプルコード

NUnit 向けのテストが入ってるけど、先頭行の [Test] と aes_encrypt_decrypt_sample() メソッドの Assert.AreEqual(str, decoded); を削除すれば問題なく動く。

using System.IO;
using System.Security.Cryptography;

private byte[] _key;
private byte[] _IV;

[Test]
public void aes_encrypt_decrypt_sample() {
    string str = @"対称アルゴリズムでの暗号化では、ストリームが利用されます。ストリームを利用することで、データ用の中間ストレージも必要とせず、様々なデータ アクセスの手法を提供します。また、対称アルゴリズム、ハッシュアルゴリズムで共通の CryptoStream を利用することで、より使いやすいインタフェースを提供します。";

    RijndaelManaged aes = new RijndaelManaged();
    aes.GenerateKey();
    aes.GenerateIV();
    _key = aes.Key;
    _IV = aes.IV;

    string encoded = encrypt(str);
    string decoded = decrypt(encoded);
    Assert.AreEqual(str, decoded);
}

/// <summary>
/// 文字列を暗号化
/// </summary>
/// <param name="str"></param>
/// <returns></returns>
private string encrypt(string str) {
    byte[] source = Encoding.Unicode.GetBytes(str);
    RijndaelManaged aes = new RijndaelManaged();
    byte[] destination;
    using (MemoryStream ms = new MemoryStream())
    using (CryptoStream cs = new CryptoStream(ms, aes.CreateEncryptor(_key, _IV), CryptoStreamMode.Write)) {
        cs.Write(source, 0, source.Length);
        cs.FlushFinalBlock();
        destination = ms.ToArray();
    }
    return Encoding.Unicode.GetString(destination);
}

/// <summary>
/// 文字列を復号化
/// </summary>
/// <param name="str"></param>
/// <returns></returns>
private string decrypt(string str) {
    byte[] source = Encoding.Unicode.GetBytes(str);
    RijndaelManaged aes = new RijndaelManaged();
    byte[] destination;
    using (MemoryStream ms = new MemoryStream())
    using (CryptoStream cs = new CryptoStream(ms, aes.CreateDecryptor(_key, _IV), CryptoStreamMode.Write)) {
        cs.Write(source, 0, source.Length);
        cs.FlushFinalBlock();
        destination = ms.ToArray();
    }
    return Encoding.Unicode.GetString(destination);
}

実際に使う場合は引数や戻り値はバイト配列の方がいいだろうけど、サンプルとして書きやすいので string にした。

2005-08-04 (Thu)

* C# で文字列と byte 配列の変換

この記事の直リンクURL: Permlink | この記事が属するカテゴリ: [.net] [C#]

C# でもバイト配列を使う機会は意外と多い。

C# で文字列を byte の配列に変換するには System.Text.Encoding.Unicode.GetBytes メソッドを使う。

using System.Text;

string str = "文字列";
byte[] byteArray = Encoding.Unicode.GetBytes(str);

byte の配列から string に変換するには System.Text.Encoding.Unicode.GetString メソッドを使う。
string strFromByte = Encoding.Unicode.GetString(byteArray);

System.Text.Encoding には Unicode 以外の文字コードを扱うためのプロパティも用意されている。

2005-07-28 (Thu)

* C# で危険なメソッドが呼ばれたときに警告を出す

この記事の直リンクURL: Permlink | この記事が属するカテゴリ: [C#] [.net] [プログラミング]

「使い方によっては危険なメソッド」が呼ばれたときに、呼んだプログラマに対してなんらかの警告を出したい。できるならば、プログラムを実行する前に。

- 危険なメソッドが呼ばれたら警告を出したい

C++ で書かれたとある通信用 DLL ファイルがある。その 通信用 DLL を直接呼ぶとリソースの管理やマーシャリングが面倒なので、C# でラッパーを書いた。そのラッパーは、いろんな開発者に渡して使ってもらうことになる。ただ、ラッパーのソースを渡すことはできないので、コンパイルしたアセンブリとして配布する。

その後、C++ で書かれた通信用 DLL の特定の関数にバグがあることがわかった。一定回数以上その関数を呼ぶと、エラーしか返らなくなるというものだ。その関数はラッパー上では DllImport 属性でインポートしているだけなので、もとの DLL のバグが修正されない限りはバグが発生する。バグに当たるのを避けるため、C# で作ったラッパーの利用者に「その関数を使うのは危険だよ、呼ぶのは一定回数以内で済む場合だけにしてね」という警告を出したい。

できれば、コーディング中にそのメソッドを呼ぶコードを書いたら警告を出すとか、もしくは、コンパイル時に警告を出すようにしたい。実行時に警告を出すのでは遅すぎる。さて、どうするのがいいだろう。

- Obsolete 属性を付ければ警告を出せるけど、意味が違う

後輩はラッパーの該当メソッドに Obsolete 属性を付けることでこの問題に対処した。

C# プログラマーズ リファレンス Obsolete
http://www.microsoft.com/japan/msdn/library/ja/csref/html/vc ...

これなら、このメソッドを呼んでいる場合、コンパイル時に警告が出る。期待する動作だ。でも、意味が違う。Obsolete は「もう使われていない,すたれた;時代[流行]遅れの;役に立たない,不用の」といった意味だ。将来的に削除予定のメソッドにつける属性を、期待する動作をするからといって付けてしまうのは美しくない。それを許したら、「警告を出す」という目的のために属性が使われてしまう。

何か他に良い属性は無いかと思い、MSDN のドキュメントを探してみたが、良さそうなものがない。Alert 属性とか Critical 属性とか Warning 属性とか、Danger 属性とか Notice 属性とかないのかなあ。syslog だとあと EMERG と ERR と DEBUG があるけど、それはいらないな。カスタム属性を作る? うーん、この一か所だけのためにそうするのは手間だなあ。

XML ドキュメントコメントの ///<summary> </summary> に警告文を書いておけば、インテリセンスには表示される。しかし、それだけだと XML ファイルが参照されなかったり、何らかの理由でインテリセンスが表示されなかったときに対応できない。2004-08-25 の「DataSet でインテリセンスが効かない」みたいな現象が起きたときに困る。

- #warning は期待する動作ではない

Google で 属性 警告 生成 C# を検索すると、@IT の文書がヒット。

連載:C#入門 第19回 プリプロセッサとドキュメント
http://www.atmarkit.co.jp/fdotnet/csharp_abc/csharp_abc_019/ ...
自作のエラーや警告を発する

込み入ったプログラムを記述していると、C#の文法エラーではないが、プログラムの意図として間違いだとプログラマに伝えたい場合がある。特に個人ではなくチームで開発していると、他のプログラマに間違った使い方をさせないために、このような措置が必要とされることがある。これを実現するために、C#のプリプロセッサには、警告を発する「#warning」と、エラーを発する「#error」が用意されている。以下はそれを用いた例である。

#warning ってのがあるのか。なになに、以下のようにソース中に書くと、続く文字列を警告してくれると。

#warning This is a sample warning.

よしやってみよう。警告文をソース中に埋めて、と。あ、VS.NET 2003は 警告文に下線まで引いてくれるのね。コンパイル。おおっ、ちゃんと警告が出たー! 警告文字列は日本語でも大丈夫なんだね。って、ちょっと待て。これって危険なメソッドを呼んだ方のソースのコンパイル時じゃなくて、元のソースがコンパイルされたときに警告されるわけじゃん。いや、私はこのメソッドの危険性はわかってるんだってば。このメソッドを含んだ DLL の利用者に警告を送りたいのに、これじゃ意味がない。

- もう Obsolete 属性でいいよ

MVP (Microsoft Most Valuable Professional) の C# を持ってる人に聞いたり、Web の文書を探してみたが、結局有効な代案を見つけられなかった。私は実利主義。仕方がないので結局 Obsolete 属性を付けることにした。ただ、///<summary> </summary> のコメントには、Obsolete 属性を付けてるけど削除予定はないよ、ということを記述した。

2005-06-27 (Mon)

* DateTime.Parse と DateTime.ParseExact の違い

この記事の直リンクURL: Permlink | この記事が属するカテゴリ: [.net] [C#]

日付を表現する文字列をパースして DateTime 構造体を作ってくれる DateTime.Parse()と DateTime.ParseExact() について。

書式が決まってるんだったら、速度が速くて厳密な ParseExact() 使えとのこと。あー、私はずっと Parse() 使ってたよ。

Figures
http://www.microsoft.com/japan/msdn/msdnmag/issues/05/03/Cul ...
Parse と ParseExact の比較

  文字列を解析するためのメソッドとして、Parse と ParseExact の 2 つが用意されています。Parse メソッドの機能は COM に根差しており (COM 自体は旧バージョンの Visual Basic に根差しています)、処理コストの程度にかかわらず文字列から日付への変換が行われました。不適切な文字列解析を行うことのリスクは、処理に悪影響が伴うことにあります。この悪影響の 1 つは、dd/mm/yy や mm/dd/yy の日付書式を指定する場合に明らかとなります。Microsoft .NET Framework に用意されている DateTime.Parse メソッドは、以前のメソッドとほぼ同じ目的に使用されますが、残念なことに以前と同じ問題をいくつか抱えています。余分なチェックが行われるため処理に時間がかかり、正しく検出されない新しい書式は今後も常にいくつか存在します。覚えているかもしれませんが、こうした動作を "邪悪な日付解析" と侮蔑的に呼ぶことがありました。
  一方、DateTime.ParseExact メソッドは、DateTimeFormatInfo オブジェクトで指定された正しい書式を受け取り、その書式を使用して処理を行うだけです。書式に一致しないデータが処理されることはありません。また、余分なスペースを許容するかどうかを巡る興味深い議論がマイクロソフト社内で行われています。簡単に言うと、ParseExact メソッドの目的は、"書式があり、その書式が設定された文字列がある場合に、解析を実行する" という流れに沿っています。ParseExact を使用することで処理速度が高速化され、セマンティックとしてもより正確になります。そのため、DateTime.Parse メソッドの柔軟性が不必要な場合には ParseExact メソッドを使用することを強く推奨します。

多機能な CultureInfo クラスを利用して .NET の世界を身近なものにする から。
http://d.hatena.ne.jp/atsushieno/20050625/p1

2005-06-08 (Wed)

* NUnit を使った開発とテスト

この記事の直リンクURL: Permlink | この記事が属するカテゴリ: [C#] [.net] [プログラミング]

C# でクラスライブラリを開発することになった。テスティングフレームワークである NUnit を使ってテストコードを書きながら開発したい。

- NUnit を使うと何がいいのか

テストの結果を可視化しやすい。
NUnit というフレームワークに則ってテストできる。

上記二点がテスティングフレームワークを使う理由。

「テストコードを使って、自動的にテストができる」というのは、テスティングフレームワークの利点ではない。「コードをテストするためのコード」すなわちテストコードを書いてテストするというのは、プログラマなら無意識にやってるはず。

テスティングフレームワークは、テストコードの書き方とテスト結果の出力形式を規定してくれるだけ。些細なことに思えるかもしれないが、この規定するということは重要なことだ。テスティングフレームワークを使わずに独自のルールに則って書かれたテストコードは、テスティングフレームワークのルールに則って書かれたテストコードに比べると、書いた人以外には理解しにくい。テスト結果の出力形式についても同様。

テスティングフレームワークを使って書かれたテストコードは、その構造についてある程度予想がつく。テスト結果の出力についても、どこに注意を向ければよいかわかる。ルールに則って書かれてるんだから当たり前。それがテスティングフレームワークを使う理由だ。もちろん、テスティングフレームワークが提供する便利な機能を利用するのも理由の一つではある。

たとえば、ASP.NET を使わなくてもウェブアプリケーションは書ける。でも、ASP.NET を使うとフレームワークに則ったウェブアプリケーションを書ける。その結果、アプリケーションは共通の基盤に則った構造を持ち、構造と出力形式について予想が付く。

- NUnit のインストール

NUnit のインストールは超簡単。

NUnit - Home
http://nunit.org/

ダウンロードページから NUnit-2.2.0.msi http://www.nunit.org/downloads/NUnit-2.2.0.msi をダウンロード。Next 連打でインストール完了。

- NUnit の使い方の概要

NUnit がやってくれるのは、ルールに則って書かれたテストコードを実行してその結果を表示してくれることだけ。テストコードは NUnit が自動生成してくれるわけじゃないので、自分で書く必要がある。NUnit を使ったテストしながらの開発は、以下のような流れで進む。

テストコードを書く。
ここで NUnit でテストを実行。テストが失敗することを確認する。実装がないので、すべてのテストが失敗するはず。

適宜 NUnit でテストを実行しながら実装コードを書く。
全部のテストが成功すれば完了。

- NUnit の使い方の具体例

実装コード用のクラスとは別に、テストコードを記述したクラスを用意する。

テストコードを記述したクラスから、実装コードを記述したクラスを「プロジェクト参照」で参照する。
ソリューションエクスプローラ上にある、テストコードを記述したクラスの「参照設定」を右クリックして「参照の追加」を選択。「プロジェクト」タブから実装コードを記述したクラスを選択する。

テストコードを記述したクラスから、NUnit の DLL を参照する。
ソリューションエクスプローラ上にある、テストコードを記述したクラスの「参照設定」を右クリックして「参照の追加」を選択。「.NET」タブから nunit.framework を選択する。
テストコードを記述したクラスで using NUnit.Framework; を追加しておく。

実装コードを記述したクラスと、テストコードを記述したクラスの名前空間は同じものにしておく。

いちおうこれで準備完了。

- NUnit GUI の自動起動

デバッグ実行時に NUnit GUI が起動するように設定する。これをやらなくても NUnit を使うことはできるけど、やっておいた方が便利。

ソリューションエクスプローラから、テストコードを記述したプロジェクトのプロパティを開く。
構成プロパティのデバッグの開始動作のデバッグモードを「プロジェクト」から「プログラム」に変更して適用ボタンを押す。
デバッグモードが「プログラム」になると、スタートアプリケーションのパスを指定できるようになるので、NUnit GUI のパスを指定する。私は以下をコピー & ペーストした。
C:\Program Files\NUnit 2.2\bin\nunit-gui.exe

あとはテストコードを記述したプロジェクトを「スタートアッププロジェクト」に指定してデバッグ実行すると、自動的に NUnit GUI が立ち上がる。ただ、立ち上がるだけで自動的にテストを実行してはくれないみたい。自動的にやる方法はあると思うけど調べてない。

2005年06月15日追記。自動起動するように設定するよりも、NUnit GUI あらかじめ起動しておく方が私に合っていることに気づいた。2005-06-15 の「NUnit はテストコードの更新を自動検出してくれる」を参照。

- NUnit 用のテストコードの書き方の概要

[TestFixture] 属性を付けたクラスは、テストクラスとして NUnit に認識される。
[Test] 属性を付けたメソッドは、テストメソッドとして NUnit に認識される。
[Test] 属性を付けたメソッド中で NUnit.Framework.Assert() を使って値をテストする。

2005-06-01 (Wed)

* DataGrid で行番号を表示する

この記事の直リンクURL: Permlink | この記事が属するカテゴリ: [.net] [C#]

ASP.NET の DataGrid で行番号をデータバインドで表示する方法。

行番号を取得できるプロパティがありそうなものだけど、見つけられなかった。ItemIndex が使えるかなと思ったが、0 から始まるのでそのままでは使えない。仕方がないので、以下のような場当たり的なコードを書いた。うーん、美しくないよなあ。

<asp:TemplateColumn HeaderText="行">
<ItemTemplate>
<asp:Label id=Label1 runat="server" Text='<%# int.Parse(DataBinder.Eval(Container, "ItemIndex").ToString()) + 1 %>'></asp:Label>
</ItemTemplate>
</asp:TemplateColumn>

上記コードを書いて心を痛めていたところ、心優しい後輩が int.Parse() を使わずに直接キャストしても問題ないと教えてくれた。確かにこのパターンならキャストエラーが出ることなんてあり得ないので、直接キャストすればいい。おかげでコードがちょっとだけ短くなった。
<asp:Label id=Label1 runat="server" Text='<%# ((int) DataBinder.Eval(Container, "ItemIndex")) + 1 %>'>

つまり、私は C# のキャストやボクシング・アンボクシングについて理解してないってこと? 調べなきゃ。

調べなきゃ、と思ってたらまた別の心優しい後輩が教えてくれた。
<asp:Label id=Label1 runat="server" Text="<%# (Container.ItemIndex + 1).ToString() %>">

コンテナに直でアクセスするという方法。DataBinder.Eval を使うと型を解決するためのリフレクションが発生するので速度的に不利になるとのこと。なるほど、そういうものなのか。今回の案件では件数がごく少ないのであんまり変わらないだろうけど。

さらに試したら以下で十分な模様。最初に比べるとずいぶん短くなったなー。
<asp:Label id=Label1 runat="server" Text="<%# Container.ItemIndex + 1 %>">

2005-05-25 (Wed)

* マルチスレッドでデータの不整合を防ぐための排他制御 .NETマルチスレッド・プログラミング入門 第3回

この記事の直リンクURL: Permlink | この記事が属するカテゴリ: [C#] [.net]

@IT:連載:.NETマルチスレッド・プログラミング入門 第3回 マルチスレッドでデータの不整合を防ぐための排他制御
http://www.atmarkit.co.jp/fdotnet/mthread/mthread03/mthread0 ...
private void ThreadMethod()
{
  int result = bank.AddBalance(200);
  Console.WriteLine("{0}: bank.Balance + 200 = {1}", name, result);
}

AddBalance() してから Console.WriteLine() するまでの間に、他スレッドが AddBalance() したら値がずれる・・・と思ったけど AddBalance() って戻り値があってそれを表示してるだけか。なら問題ない。スレッド周りはついつい過敏に反応してしまう。

2005-04-12 (Tue)

* C# でマルチスレッド 非同期デリゲート編

この記事の直リンクURL: Permlink | この記事が属するカテゴリ: [.net] [C#]

C# でスレッドを使う手法のメモ。今回はデリゲートを使うやり方。

- 非同期デリゲートを使ったマルチスレッドの特徴

スレッドプールで実行される。
引数を渡せる。
戻り値を取り扱える。コーディングが煩雑になるのでやったことないけど。
例外ハンドリングができる。

非同期デリゲートは使い勝手が良い。スレッドプールの枯渇にさえ気をつけておけば非常に有用。Thread クラスを使ったマニュアルスレッドよりも制限が少なくてずっと楽だ。

- 非同期デリゲートの使い方

スレッドで実行したいメソッドと、そのデリゲートを書く。
デリゲートオブジェクトを生成し、BeginInvoke() メソッドを呼ぶ。

- 非同期デリゲートを使ったマルチスレッドプログラムのサンプルコード

メソッドのデリゲートを作って、BeginInvoke() するだけだから非常に楽。
デリゲートの名前は 元のメソッド名 + Delegate にしておくとわかりやすい。Worker だったら WorkerDelegate だ。

using System;
using System.Threading;

namespace AsyncDelegate {
    /// <summary>
    /// Class1 の概要の説明です。
    /// </summary>
    class Class1 {
        /// <summary>
        /// アプリケーションのメイン エントリ ポイントです。
        /// </summary>
        [STAThread]
        static void Main(string[] args) {
            WorkerDelegate del = new WorkerDelegate(Worker);
            del.BeginInvoke("This thread is worker thread", null, null);

            for (;;) {
                Console.WriteLine("This thread is main thread");
                Thread.Sleep(573);
            }
        }

        private delegate void WorkerDelegate(string message);
        /// <summary>
        /// ワーカースレッド
        /// </summary>
        /// <param name="message"></param>
        private static void Worker(string message) {
            for (;;) {
                Console.WriteLine(message);
                Thread.Sleep(1701);
            }
        }
    }
}

2005-01-20 (Thu)

* C# でアプリケーションの終了コードを返す

この記事の直リンクURL: Permlink | この記事が属するカテゴリ: [C#] [.net]

Main 関数の戻り値がアプリケーションの終了コードになる。終了コードは復帰値やエラーコードなどとも呼ばれる。

- void Main のとき

終了コードは0になる。例外を catch せずに終了した場合でも0。

- int Main のとき

戻り値が終了コードになる。
[STAThread]
static int Main(string[] args) {
    int exit_status_code = 1;
    return exit_status_code;
}

- 上記を実行してみる

上記ソースをビルドして cygwin から実行してみる。$? は直前のコマンドの終了コードが格納されている。
$ ./ExitStatus.exe

$ echo $?
1
1 が返ってきている。

- サンプル

組み込むときはこんな感じかな。
[STAThread]
static int Main(string[] args) {
    int exit_status_code = 0;
    try {
        // 処理
    } catch {
        exit_status_code = 1;
    }
    return exit_status_code;
}

追記。他の方法もある。

- System.Environment.Exit() の引数として終了コードをセットする

System.Environment.Exit(1) だと終了コード 1 でアプリケーションを終了する。

Environment.Exit(1);

System は省略した方がちょっとだけ楽。

- System.Environment.ExitCode に終了コードをセットする

System.Environment.ExitCode プロパティに終了コードをセットしておく。
ロギングなどに使う場合は System.Environment.Exit() だと本当に終了してしまう。値の読み書きができるこちらの方が便利。

2005-01-13 (Thu)

* C# で数値を書式指定して文字列出力する サンプル

この記事の直リンクURL: Permlink | この記事が属するカテゴリ: [C#] [.net]

書式指定をつけて数値を文字列化して出力するサンプルコードのメモ。C や Perl の printf みたいなもの。

- String.Format による書式付き出力

先輩は以下を見て「Java みたいだな」と言ってた。Java ってこういう指定の仕方をするらしい。
const string tmplt = @"数字を書式指定して出力: {0:d} {0:f} {0:c}  桁も指定: {0:d4} {0:f5} {0:c6}";
Console.WriteLine(tmplt, 123);

出力結果。
数字を書式指定して出力: 123 123.00 \123  桁も指定: 0123 123.00000 \123.000000

- Tostring(stirng format) で書式指定出力

ToString には書式指定できるオーバーロードがあるので手軽。

Console.WriteLine(123.ToString("d8"));

出力結果。
00000123

- 文字列の場合

文字列だったら s だ。以下の記述では桁の指定は反映されなかったけど。
const string tmplt_string = @"文字列 {0:s} 桁も指定: <{0:s8}>";
Console.WriteLine(tmplt_string, "Love");

出力結果
文字列 Love 桁も指定: <Love>

- 数値書式指定文字列 のリファレンスから抜粋

標準の数値書式指定文字列
http://www.microsoft.com/japan/msdn/library/ja/cpguide/html/ ...
C または c 通貨
D または d 10 進数
E または e 指数
F または f 固定小数点

この他にもパーセントとか16進数で出力とかいろいろあった。

上記ページにあった出力サンプル。
[C#]
using System;
using System.Threading;
using System.Globalization;

class Class1
{
    static void Main()
    {
        Thread.CurrentThread.CurrentCulture = new CultureInfo("en-us");
            double MyDouble = 123456789;

        Console.WriteLine("The examples in en-US culture.\n");
        Console.WriteLine(MyDouble.ToString("C"));
        Console.WriteLine(MyDouble.ToString("E"));
        Console.WriteLine(MyDouble.ToString("P"));
        Console.WriteLine(MyDouble.ToString("N"));
        Console.WriteLine(MyDouble.ToString("F"));

        Thread.CurrentThread.CurrentCulture = new CultureInfo("de-DE");
        Console.WriteLine("The examples in de-DE culture.\n");
        Console.WriteLine(MyDouble.ToString("C"));
        Console.WriteLine(MyDouble.ToString("E"));
        Console.WriteLine(MyDouble.ToString("P"));
        Console.WriteLine(MyDouble.ToString("N"));
        Console.WriteLine(MyDouble.ToString("F"));
    }
}
上記のコード例によってコンソールに表示される出力を次に示します。

The examples in en-US culture:
$123,456,789.00
1.234568E+008
12,345,678,900.00%
123,456,789.00
123456789.00
The examples in de-DE culture:
123.456.789,00 DM
1,234568E+008
12,345,678,900.00%
123.456.789,00
123456789,00

2004-12-21 (Tue)

* C# の using ステートメントによる Dispose()

この記事の直リンクURL: Permlink | この記事が属するカテゴリ: [C#] [.net]

C# で using ステートメントを使うと、ステートメント終了時にオブジェクトの Dispose() を保証できる。

- アンマネージリソースは明示的に解放しなければならない

マネージリソースであればガベージコレクタが解放してくれる。しかし、データベースコネクションやファイルハンドルなど、アンマネージなリソースは使い終わったら Close() や Dispose() などで明示的に解放する必要がある。解放を怠るとリソースが枯渇してしまうおそれがある。

アンマネージリソースを使う場合、try finally ブロックを作って解放処理が必ず実行されるようにするのが基本。
SqlConnection con = new SqlConnection(DBConnectionString);
con.Open();
try {
    // DB アクセスなどの処理
} finally {
    con.Close();
}

C# では using ステートメントを使って以下のように書くことができる。
using (SqlConnection con = new SqlConnection(DBConnectionString)) {
    con.Open();
    // DB アクセスなどの処理
}

using ステートメント
http://www.microsoft.com/japan/msdn/library/ja/csref/html/vc ...
using ステートメントでインスタンスを作成して、using ステートメントの終了時に Dispose メソッドが呼び出されることを保証します。using ステートメントが終了するのは、using ステートメントの末尾に到達したときか、例外がスローされたなどの理由で、ステートメントの末尾に到達する前に制御がステートメント ブロックを離れたときです。

インスタンスを作成するオブジェクトには、System.IDisposable インターフェイスが実装されている必要があります。

MS の文書にもあるとおり、using ステートメントは IDisposable インターフェイス が実装されているオブジェクトでのみ利用できる。アンマネージリソースを扱うクラスを書いたときには、IDisposable インターフェイスを実装しておくと良い。せっかくシンタックスシュガーが用意されてるんだから、使わない手はない。

- using エイリアスや using ディレクティブとは別物

名前空間についての記述である using ディレクティブとは別物。
using System.Data; // これとは別物

using ディレクティブ
http://www.microsoft.com/japan/msdn/library/ja/csref/html/vc ...
名前空間のエイリアスを作成する場合 (using エイリアス)。
名前空間で型の使用を許可する場合。これにより、その名前空間内では、型を修飾しないで使用できます (using ディレクティブ)。

初めて using ステートメントを見たときは、なんでこんなところで名前空間を操作してるんだ? と疑問に思ったものだ。

- using ステートメントを使うと何がうれしいのか

解放のための finally を書かなくて良い。
アンマネージリソースの解放忘れを防止できる。アンマネージリソースを割り当てたとき、漏れなく解放しているかどうかソースをチェックするのは手間がかかる。using ステートメントなら割り当てるコードと一体化しているので漏れが無くなる。

オブジェクトのスコープがはっきりする。
これは人によってはそう思わないかもしれない。
VS.NET を使っていると using ステートメントを使うとインデントが付く。多重ループや深い条件分岐などでインデントが深いコードというのは非常に可読性が悪いとされる。私もインデントの深いコードには近寄りたくない。しかし、なぜか私は using によるインデントは気にならない。オブジェクトのライフタイムを端的に表すインデントだからだろうか?

- using をまとめて書く

using はまとめて書くことができる。後に書いた物ほど先に解放される。
using ( ... )
using ( ... )
using ( ... ) {

}

複数のアンマネージリソースを割り当てるときなどは便利。

- using を使った DB トランザクションのテンプレート

私がデータベーストランザクションを実行するときのテンプレート。実際には SqlCommand クラスとか DataAdapter を使ったりするけど基本はこれ。

using (SqlConnection con = new SqlConnection(DBConnectionString)) {
    con.Open();
    using (SqlTransaction tran = con.BeginTransaction(IsolationLevel.Serializable)) {
        try {
            // データベーストランザクションを実行
            tran.Commit();
        } catch {
            tran.Rollback();
            throw;
        }
    }
}

上記コードをテンプレートとして使ってはいるが、私はこのコードに疑問を持っている。それについてはまた後日。

2004-10-19 (Tue)

* C# の Edit and Continue をサポートする VS2005

この記事の直リンクURL: Permlink | この記事が属するカテゴリ: [.net] [C#]

VS.NET が C# の Edit and Continue をサポートするようになるとのこと。

C# Edit and Continue announced!!!!
http://blogs.users.gr.jp/daigoh/archive/2004/10/16/5406.aspx
皆さんからのリクエストが多かったC# Edit and Continueが次のCommunity Dropから使えるようになります。

Edit & Continue 裏話
http://blogs.users.gr.jp/daigoh/archive/2004/10/16/5412.aspx
C# Edit & ContinueをVS2005に入れることが決まったのがMVP Summitの約一週間前です。Beta1に間に合うよう自分も含めて6人の開発チームが結成されました。

MSDN Feedbackおそるべし (E&C 裏話 其の2)
http://blogs.users.gr.jp/daigoh/archive/2004/10/16/5417.aspx
VBがWhidbeyの最初からE&Cをやっていたので.NET RuntimeとDebuggerのバグは多分無いだろうと甘く見ていたのですが、これがまた物凄い数。おかげで、最新のビルドではかなり製品版に近いクオリティなのですが、CTDではバグが残っています。

- Edit and Continue ってなに?

ここまで書いておいてこんなこと言うのもなんだけど、Edit and Continue ってなに? 編集と続行? ランタイムとデバッガの話をしてるみたいだけど何だろう? デバッグ中のコードを編集して、実行を継続できるの?

Google で Edit and Continue を検索したら MS のサイトがヒット。文書の日付が1998年!? 古いなあ。古き良き時代の機能なのか? 真空管のアンプみたいな。

Microsoft Visual C++ Web Site
http://www.microsoft.com/japan/msdn/vs_previous/visualc/tech ...
エディット・コンティニューは、Microsoft Visual C++ version 6.0開発システムに追加された新しいデバッギング機能です。これにより、デバッギング セッションの途中でソース コードを変更し、デバッグ対象のアプリケーションにコードの変更を適用することができます。この際には、デバッギングを停止し、リビルドを行い、デバッガを再起動し、アプリケーションをバグが発生した状態にまで進めるといった操作は必要ありません。

すごいじゃん。なんて先進的で富豪的な機能だ。「エディット・コンティニューの制限」を読むと、例外処理ブロックを変更できないなどの制限があるようだけど、開発効率を上げるのは間違いない。でも、こんな機能付いてるとますます行き当たりばったりのコーディングが許容されてくるなあ。それが時代の流れなんだろうけど。

心配なのはどのぐらいのマシンパワーを要求されるかだ。今使ってる Visual Studio .NET 2003でさえ Celeron 1.7GHz の開発マシンでは重くて仕方がないのに、Visual Studio 2005ってどのくらいのマシンパワーがいるんだろう?

2004-08-25 (Wed)

* DataSet でインテリセンスが効かない

この記事の直リンクURL: Permlink | この記事が属するカテゴリ: [.net] [C#]

プラトンが言ったように、人間は不完全だ。不完全だからこそ補完が必要。2004-08-02 の「cygwin で /cygdrive を bash の補完対象にする」も補完にかける情熱の産物だ。

というわけで、Visual Studio .NET 2003 の補完機能「インテリセンス (IntelliSense)」はいつも便利だと思ってる。Delphi 5 を使っていたときも補完を活用していたが、VS.NET 2003 の補完は Delphi 5 の上を行く。発表年が5年ほど違うので新しい方が高機能なのは当たり前だけど。あ、私は統合開発環境って Delphi5 と VS.NET くらいしか常用していなかったので、 Eclipse などの補完機能については全く知らない。

補完機能を駆使してコーディングしてるとタイプミスを大幅に減らせるし、長いクラス名やメンバ名を使うときの心理的障壁を下げられる。実に生産的な機能だ。

- なんで補完できないの?

自分で作成した DataSet の Table や Row を補完したいが、なぜかインテリセンスが効かない。CTRL + SPACE を押しても無反応。ディスクアクセスしてる様子もない。このメンバは補完できないといった感じ。

System.Web 名前空間のクラスやインスタンスのメンバは問題なく補完できるのに、なぜか自分で作成した DataSet のメンバを表示させようとしても、うんともすんとも言わない。

- 先達の叡智を検索

Google で Intellisense DataSet を検索。および Google でインテリセンス DataSet を検索
DataSet をカタカナのデータセットにして検索してもあまり有用なサイトは見つからなかった。

DataSetのIntelliSenseが働かない
http://hp.vector.co.jp/authors/VA019702/csharp/cs002.html
で、IntelliSenseの話に戻るが、C#の開発環境とはこういうものらしい。
解決策としては、ソリューション全体をリビルドしてやればいい。ソリューションが何千ファイルも抱える場合リビルドにはためらいがあるかもしれないが、IntelliSenseを欠く開発効率の悪さを考えるなら、惜しむ労力でもないだろう。

DataSetのDataRowでインテリセンスが効かない(VisualStudio.Net2003)
http://blogs.users.gr.jp/naka/archive/2004/04/10/1887.aspx

パラメータ・ヒントがうまく動作しない時は
http://www.kumei.ne.jp/c_lang/netinteli.htm
[C++]
.ncb ファイルに問題がある場合

プロジェクト ディレクトリのルートにある .ncb ファイルが読み取り専用であるか
破損している場合、IntelliSense の情報は使用できません。この問題を修復するには、
次の処理を行います。

ソリューションを閉じます。
.ncb ファイルを削除します。
再びソリューションを開きます。
再びソリューションを開くと、.ncb ファイルが新規作成されます。

言われたとおり、ncbファイルを削除するとパラメータ・ヒントがきちんと動作するようになりました。また、エラー時出力ペインの指摘箇所をクリックしても「xxは違うプロジェクトで・・」のメッセージボックスも出なくなり快適な環境となりました。(メデタシ、メデタシ)

.ncb ファイルが見つからなかったので上記方法は試していない。

くだすれC#(Part3)
http://pc2.2ch.net/tech/kako/1047/10472/1047210828.html
88 名前: デフォルトの名無しさん 投稿日: 03/04/08 02:21
メンバ変数を50くらいに増やしたら
突然、インテリセンスが利かなくなったんだけど
つらいなぁ。入力中もキーワードが青じゃなくなってるし...。


89 名前: デフォルトの名無しさん 投稿日: 03/04/08 02:38
>>88
そのクラスはコンパイル通るかい?


90 名前: デフォルトの名無しさん 投稿日: 03/04/08 03:00
>>88
それうちの環境で良くある
VSを起動し直せばいい


91 名前: 85 投稿日: 03/04/08 09:02
>>86
おお、サンクス!
Bitmap側じゃなくGraphics側にメソッドがあったのか。
ControlクラスにCreateGraphics()ってのあって
これ使えばOnPaint()以外でも描けるみたい。
こっちも試してみます。

>>88
そもそもメンバ変数50個はクラスの設計的に問題ありかも。
ちなみに自分もそこまで増やしたこと無いけど
インテリきかなくなるときちょくちょくあります。
迷わず再起動。


92 名前: デフォルトの名無しさん 投稿日: 03/04/08 09:08
>>88
俺も、もっともメンバ変数の数とは無関係のような気がしないでも無い。

>>91
フォームクラスじゃ100は当たり前じゃないか?

- 対策

ウェブを見て回ってわかったが、要するにバグなんだろうね。
Visual Studio を再起動すれば直ると >>90 は言ってるけど、私の環境はそれでも直らず OS の再起動までしてやっと直った、ということがあった。

この現象が起きたときは、OS を再起動してソリューションのリビルドをすれば直るかも、ってところかな。開発環境としてはもっと安定していてほしいんだけどな。でも便利だから仕方なく使う。

- 型を間違えてると補完できないよ

最近、「自分で作った DataSet のメンバを補完できないんだけど」という相談を受けた。DataTable 名が補完されないという。典型的な上記症状だと思って対策を伝えたところ、別の原因だった。サンプルコードを以下に示す。

DataSet ds = new MyDataSet();

このあとに ds. まで入力して DataTable 名を補完しようとしたができないとのこと。DataSet 型にキャストしてるんだから、補完されないのは正しい動きだ。

MyDataSet ds = new MyDataSet();

上記のように直して解決。

2004-08-10 (Tue)

* ASP.NET でも html エスケープは必要

この記事の直リンクURL: Permlink | この記事が属するカテゴリ: [.net] [HTML] [C#]

html では、& " < > を直接記述することはできない。文法上意味を持つ文字だからだ。この文字そのものを表現したい場合は、それぞれ &amp; &quot; &lt; &gt; にエスケープする必要がある。これを怠るとセキュリティホールの原因となったり、表示が崩れたりする。ウェブアプリケーション作成の基礎であり、欠かせないものだ。

私は今回、この html エスケープについて失敗をしてしまった。今回は ASP.NET でシステムを作ったのだが、まだ ASP.NET に慣れていなかったことと、テストの時間を十分にとれなかったことが失敗の原因だ。

- DataGrid は html エスケープが必要

具体的に何をやったかというと、ASP.NET の Label コンポーネントの text プロパティに値を代入するときや、DataGrid コンポーネントにデータバインドするときに html エスケープをしなかったのだ。html エスケープは ASP.NET が勝手にやってくれると思いこんでいたからだ。

確かに、ASP.NET の TextBox コンポーネントなどであれば、value プロパティに代入した文字列の html エスケープは ASP.NET フレームワーク側で面倒を見てくれる。しかし、前述の Label や DataGrid をはじめとする一部のコンポーネントにおいては、html エスケープは自動で行われない。プログラマが責任を持ってエスケープする必要がある。

「自分のソースコード中で生成したデータで、エスケープする必要が100%ない場合はやらなくても良い。それに当てはまらない場合、出力するデータは必ず html エスケープしなさい。」とイルミ・ゾルディックくらい口を酸っぱくして後輩たちに言ってきた私がこの体たらく。実に恥ずかしいというか情けない。

ASP.NET の中でも、とくに DataGrid には注意が必要だ。DataGrid は他のコンポーネントに比べ、自動化・ウィザード化が進んでいる。DataGrid を使うと、簡単に DB にクエリを投げてそれを html テーブルとして出力する準備を整えられる。面倒な部分は Visual Studio と ASP.NET がやってくれるので、自分は SQL やストアドを書いてデータアダプタを作成し、DataGrid プロパティビルダで出力時の見栄えを整えさえすればいいと錯覚しがちだが、そうではない。html エスケープもやらなければならないのだ。

- C# で html エスケープするには

C# で html エスケープ をするには、System.Web 名前空間の HttpUtility.HtmlEncode() メソッドを使うのが簡単だ。

以下のように .aspx ファイルのデータバインド時に呼ぶようにする。
<%# HttpUtility.HtmlEncode(DataBinder.Eval(Container, "DataItem.subject").ToString()) %>

もしくは、.aspx.cs でデータソースからデータを取り出した後、DataBind() を呼ぶ前にデータセットの各レコードのカラムを HttpUtility.HtmlEncode() する。DataGrid のプロパティに html エスケープするか否かを設定できるオプションなどがあっても良さそうなものだが、見つけることはできなかった。カスタムコントロールを作ればいいんだろうけど、標準で用意しておいて欲しかった。

System.Web.HttpUtility.HtmlEncode()
http://www.microsoft.com/japan/msdn/library/ja/cpref/html/fr ...
空白や区切り記号などの文字が HTTP ストリームで渡される場合、それらの文字は受信側で誤って解釈される可能性があります。HTML エンコーディングは、HTML では使用できない文字を等価の文字エンティティに変換します。HTML デコーディングはエンコーディングの逆の変換を行います。たとえば、テキスト ブロックに < および > という文字が埋め込まれている場合、これらの文字は HTTP 伝送用に &lt および &gt としてエンコードされます。

HttpServerUtility クラスにも同名のメソッドがあるが、ヘルプを読む限りこちらは URL エンコード用のメソッドだ。

System.Web.HttpServerUtility.HtmlEncode()
http://www.microsoft.com/japan/msdn/library/ja/cpref/html/fr ...
[Visual Basic, C#, JScript] 文字列を HTTP で送信できるようにエンコードする例を次に示します。"This is a <Test String>." というテキストを格納する文字列 TestString をエンコードし、その文字列を "This+is+a+%3cTest+String%3e." として文字列 EncodedString にコピーします。

- テスト

自分のコードが生成していない文字列を出力する部分は、以下の2つの文字列を入力してエスケープしていることを確認する。
<s>ESCAPE TEST</s>
javascript:alert('ESCAPE TEST')

<s> タグは打ち消し線を表示する。javascript:alert() はメッセージダイアログを表示する。もしこれらが機能してしまった場合、エスケープされていないことになる。

いつもはこの2つの文字列を表示させるテストを必ず行う。しかし、今回は開発に十分な時間がとれなかったこと、作ったものがアルファ版ということ、ASP.NET を過信したということが重なって失敗してしまった。

- 実際はタグを入力されると例外を出してエラー終了する設定になっていた

ここまで html エスケープについて述べてきたが、実際にはユーザ入力によるクロスサイトスクリプティングの心配はほぼ無かった。というのは、ASP.NET が持つ機能のおかげで危険な文字が入力されるのは防げていたからだ。

@ Page
http://www.microsoft.com/japan/msdn/library/ja/cpgenref/html ...
ValidateRequest
要求の検証を行うかどうかを示します。true の場合、要求の検証では、危険性のある値のリストと照合して、すべての入力データをチェックします。一致するものがあった場合は、HttpRequestValidationException クラスがスローされます。既定値は true です。
この機能は、マシン構成ファイル (Machine.config) で有効にします。この機能を無効にするには、アプリケーションの構成ファイル (Web.config) またはページで、この属性を false に設定します。

メモ  この機能を使用すると、単純なページや ASP.NET アプリケーションに対するクロスサイト スクリプト攻撃のリスクを軽減できます。ユーザー入力を正しく検証できないアプリケーションは、クロスサイト スクリプティング攻撃や SQL Server への注入攻撃など、多くの種類の不正な入力攻撃を受ける可能性があります。アプリケーション内のすべての入力フォームを慎重に評価し、検証またはコーディングが適切であることを確認したり、データを操作する前やクライアントに情報を返す前にアプリケーションが退避していることを確認したりすることが重要です。クロスサイト スクリプティングの詳細については、http://www.cert.org/advisories/CA-2000-02.html を参照してください。

ただし、この機能が働いたときは例外を出してしまうので、悪意のないユーザが html タグに似た文字列を入れることもできなくなってしまう。ValidateRequest を無効にするには、web.config で設定する。もちろん無効にした場合はアプリケーションで完璧にサニタイズしなければならない。

<!-- 危険なリクエストのチェックをしない。アプリケーション側でサニタイズする。 -->
<pages validateRequest="false"/>

validateRequest を true にしていても、エスケープは必要。データベースから取得した文字列などは、必ずエスケープしてから表示しなければならないからだ。

2004-04-07 (Wed)

* C#エッセンシャルズ 第2版

この記事の直リンクURL: Permlink | この記事が属するカテゴリ: [] [C#]

C#エッセンシャルズ 第2版C#エッセンシャルズ 第2版

ベン アルバーリ / ブラッド メリル / ピーター ドレイトン / Ben Albahari / Brad Merrill / Peter Drayton / 竹内 里佳
発売日: 2002/07


amazon で詳しく見る   bk1で詳しく見る

C# の仕様を解説。A5版で200ページ強しかないため小さくて持ち運びやすい。机上に置くリファレンス本としては良くできている。

Java や Object Pascal などのオブジェクト指向言語を使いこなしている人には、大きくてページ数が多い解説本よりもこういったリファレンスの方が使いやすい。事実、「Java は得意だけど C# はこれから使い始める」と言っていた先輩は、この本を4時間くらい読んだけでバリバリと C# でコードを書いていた。

2003-09-18 (Thu)

* C# の変数のスコープ

この記事の直リンクURL: Permlink | この記事が属するカテゴリ: [C#]

C# では、ローカル変数はどこまでスコープ内になるのか。

- 結局ブロック

ブロック単位のレキシカルスコープのようだ。
foreach ではループ変数になったら、例外的にそのブロック内に限定される。
ここら辺は perl と一緒だな。

3.7 スコープ
http://www.microsoft.com/japan/msdn/library/default.asp?url= ...

8.5.1 ローカル変数宣言
http://www.microsoft.com/japan/msdn/library/default.asp?url= ...

2003-09-16 (Tue)

* 連載 改訂版 C#入門

この記事の直リンクURL: Permlink | この記事が属するカテゴリ: [C#]

2003-07-22 (Tue)

* C# で printf デバッグ

この記事の直リンクURL: Permlink | この記事が属するカテゴリ: [C#]

// DBG
foreach (object obj in result_row.ItemArray) { //DBG
    Console.WriteLine(obj.ToString());
}

2003-07-21 (Mon)

* perl の join を C# でやってみる

この記事の直リンクURL: Permlink | この記事が属するカテゴリ: [C#]

動的に拡張できる配列があり、その中身を join するという処理を
C# で書いてみた。perl だとすごく簡潔だけど、 C# だと型の変換が面倒。
StringBuilder か何かを使えばもっと簡単に書けるのかもしれない。

static void Main(string[] args)  {
    ArrayList al = new ArrayList();
    for (int i = 0; i < 5; ++i) {
        al.Add(i);
    }
    string str = String.Join(@" OR ", (string[])al.ToArray(Type.GetType("System.String")));
    Console.WriteLine(str);
}

あ、string の配列へのキャストは、文字列定数を使わなくて済むので以下の方がきれいかな。

(string[]) al.ToArray(typeof(string));

2003-07-20 (Sun)

* C# の正規表現クラスと Group クラス

この記事の直リンクURL: Permlink | この記事が属するカテゴリ: [C#] [.net]

http://www.atmarkit.co.jp/fdotnet/basics/regex02/regex02_01. ...

C# だと、正規表現によるキャプチャを実行した場合、マッチした部分を格納するリストの0番目の要素には、マッチした部分全体が格納される。

以下のサンプルコードのように複数箇所をキャプチャする場合、最初のカッコでキャプチャした文字列が格納されるのは m.Groups[1].Value である。また、マッチしなかった場合、m.Groups[0].Value には空文字 "" が格納されてしまう。

マッチした個数によって処理を変える場合、「リストの要素数が 1より大きいかどうか」で判定しなければならない。perl と異なるので要注意。

- 正規表現によるキャプチャのサンプル

正規表現によるキャプチャのサンプル。

string str2 = "栃木県真岡市一万人町一万人プール二丁目";
string REGEX_PATTERN = @"^(栃木県|東京都)(.*)";
Match m = Regex.Match(str2, REGEX_PATTERN);
Console.WriteLine(m.Groups[0].Value);

m.Groups[0].Value は "栃木県真岡市一万人町一万人プール二丁目"、
m.Groups[1].Value は "栃木県"、
m.Groups[2].Value は "真岡市一万人町一万人プール二丁目" になる。

- 没になったコード

/*
MatchCollection mc = Regex.Matches(address1, REGEX_GET_PREF);
string s = mc[0].Value;
Console.WriteLine(s);
s = mc[0].NextMatch().Value;
Console.WriteLine(s);

Match ms = Regex.Match(address1, REGEX_GET_PREF);
Console.WriteLine(ms.Groups[0].Value);

string str2 = "栃木県真岡市一万人町一万人プール二丁目";
string REGEX_PATTERN = @"^(栃木県|東京都)(.*)";
Match m = Regex.Match(str2, REGEX_PATTERN);
Console.WriteLine(m.Groups[0].Value);
*/

2003-06-24 (Tue)

* C# で ファイルの読み書き - C# File I/O

この記事の直リンクURL: Permlink | この記事が属するカテゴリ: [C#]

後輩がファイルの書き込みができなくて悩んでたので、サンプルコードを書いてみた。

StreamWriter strm = new StreamWriter(@"c:\test.txt");
strm.Write("OK!");
strm.Close();

Close() しないと書き込みされないので注意。後輩はそれで悩んでた模様。

ファイルの読み書きするんだから明示的に書くのが当たり前なんだけど、
C# だと「ガベージコレクタがうまくやってくれるでしょ」って意識がある。
Close() してなくて書き込めてなかったことは内緒にしておいてくれ。
perl だとちゃんと書いてたんだけど、C# だと何となく甘えてしまうなあ。

MS って結構かわいそうなのかも。
できて当たり前、用意されてて当たり前、自動でやってくれて当たり前という目で見られてしまう。
「そんなメソッドが C# に無い訳がない」とか、
「Java でできるんだから C#でもできるでしょ」とか、
「商用製品なんだからそんなライブラリは用意されてて当たり前」とか。

これだけオープンソースソフトウェアが台頭していると、
それと比較されてしまうのは仕方のないことだとは思うけど。

2003-06-20 (Fri)

* C# の逐語的文字列リテラル

この記事の直リンクURL: Permlink | この記事が属するカテゴリ: [C#]

C# には「逐語的文字列リテラル」というものがある。

逐語的文字列リテラルの中ではエスケープ文字 \ による記述が無効になる。perl の "" と '' の違いみたいなものか。

"" で囲まれた文字列では \n や \t などがパースされる。
@"" で囲まれた文字列では、\n や \t などはパースされず、そのまま解釈される。
@"" で囲まれた文字列を、逐語的文字列リテラルと呼ぶ。

@"" 中で " を表現するには、"" とする。
逐語的文字列リテラルでは、以下のような記述もできる。
string j = @"one
two
three";

C# 言語の仕様 2.4.4.5 文字列リテラル
http://www.microsoft.com/japan/msdn/library/ja/csspec/html/v ...

2003-04-30 (Wed)

* C# から 接続 MS SQL Server 2000 への接続テスト

この記事の直リンクURL: Permlink | この記事が属するカテゴリ: [C#]

SqlConnection con = new SqlConnection("server=10.3.31.89;database=NorthWind;user id=sa;password=;");
SqlCommand sqlcmd = new SqlCommand("SELECT * FROM Customers;", con);
con.Open();
SqlDataReader sqldr = sqlcmd.ExecuteReader();
while (sqldr.Read()) {
    Console.WriteLine(sqldr["CompanyName"].ToString());
}
sqldr.Close();
con.Close();


すべての記事の見出し (全1029件)
全カテゴリの一覧と記事の数
カテゴリごとに記事をまとめ読みできます。記事の表題だけを見たい場合は、すべての記事の見出し (カテゴリ別表示) へ。

直近30日分の記事
2007-04-23 (Mon)
2007-03-07 (Wed)
2007-02-27 (Tue)
2007-01-17 (Wed)
2007-01-15 (Mon)
2007-01-14 (Sun)
2007-01-08 (Mon)
2006-12-01 (Fri)
2006-11-22 (Wed)
2006-11-20 (Mon)
2006-11-19 (Sun)
2006-09-30 (Sat)
2006-08-29 (Tue)
2006-08-04 (Fri)
2006-07-27 (Thu)
2006-07-23 (Sun)
2006-07-17 (Mon)
2006-07-10 (Mon)
2006-07-06 (Thu)
2006-07-03 (Mon)
2006-06-29 (Thu)
2006-06-28 (Wed)
2006-06-27 (Tue)
2006-06-25 (Sun)
2006-06-19 (Mon)
2006-06-18 (Sun)
2006-06-15 (Thu)
2006-06-11 (Sun)
2006-06-01 (Thu)
2006-05-30 (Tue)
プロファイル
斎藤 宏明。エンジニアです。宇都宮市に住んでいます。
リンク
RSS
スポンサードリンク
Powered by
さくらインターネット

© 斎藤 宏明 Saito Hiroaki Gmail Address
Landscape - エンジニアのメモ http://sonic64.com/
Landscape はランドスケープと読みます。
ひらがなだと らんどすけーぷ です。