C# Notes

概要

C# (.NET Framework) のプログラミングに関するメモ書きです。

非推奨属性をメンバーに付ける

アプリケーションではなくライブラリやフレームワークといったソフトウェアを作っていると、 仕様変更や機能拡張によってクラスやメソッドが 「以前は問題無く使えたけれども今は使って欲しくない」 状態になることがあります。 そのような場合はドキュメントに「非推奨です」と書くのがまず最初に思いつく対策ですが、 そうしてもプログラム的には何の制約もかからないので結局 「非推奨になっていることに気付かない」 人が出てきます。 まあ気付かなくても仕方ないですね。

そこで、Obsolete 属性を非推奨のクラスやメソッドの定義に付けると、 そのクラスやメソッドを使っている場所でコンパイラから警告を出させることが可能になります。 なお、Obsolete 属性を使うときにパラメータ指定してやれば警告のかわりにコンパイルエラーを起こさせるようにもできます。 例としてライブラリ中のクラス Hoge より効率が良く汎用性も高い新しいクラス Piyo をバージョン 1.2 から導入することになった場合、 次のように使います。

  1. バージョン 1.2 ではクラス Hoge に非推奨属性(警告)を付ける
  2. バージョン 1.3 ではクラス Hoge に非推奨属性(エラー)を付ける

非推奨と指定されたクラスを使うことに対する警告の度合いが二段階あるため、 「導入バージョンでは警告、その次のバージョンでエラー」 とすれば移行期間を確保できます。 なお、C# でクラスに属性を付ける書式は次のようになります。

[Obsolete("Piyo クラスを代わりに使ってください。", false)]
class Hoge
{
    ...
}

ListViewへ項目を追加する速度

ListView.Add を何度も呼び出すよりも、ListView.AddRange で一括して追加した方が速く項目を追加できます。例として、パス C:\WINDOWS\system32 にあるファイルの名前を一覧表示するコードを書いてみます。

便宜上、_ListView という ListView オブジェクトがあるものとします。その上でファイル名を一つずつ追加していくロジックを次に示します。

//using System.IO;
//using System.Windows.Forms;
ListViewItem item;
string[]     entries;

// ファイルシステムエントリーを一覧表示
entries = Directory.GetFileSystemEntries( "C:\\WINDOWS\\system32" );
foreach( string entry in entries )
{
    item = new ListViewItem();
    item.Text = Path.GetFileName( entry );
    _ListView.Items.Add( item );
}

続いて、AddRange を使って一括でファイル名を追加するロジックを次に示します。

//using System.IO;
//using System.Collections;
//using System.Windows.Forms;
ArrayList    items = new ArrayList();
ListViewItem item;
string[]     entries;

// ファイルシステムエントリーを検索
entries = Directory.GetFileSystemEntries( "C:\\WINDOWS" );
foreach( string entry in entries )
{
    item = new ListViewItem();
    item.Text = Path.GetFileName( entry );
    items.Add( item );
}

// 検索したエントリーを一覧表示
_ListView.Items.AddRange(
        (ListViewItem)items.ToArray( typeof(ListViewItem) )
    );

両ロジックの速度を、私の環境で実行した場合の所要時間で比較してみました。それぞれ5回ずつ実行して所要時間の平均を取り、それを比較したところ、前者は 3.73 秒、後者は 0.76 秒という結果になりました。話にならない程に違います(苦笑)。なお、実験環境の C:\WINDOWS\system32 には 2677 項目のファイルがあり、全ファイル名を一つの文字列に結合すると 31 KBytes 程度になる環境でした。

個別に追加した方がコーディング的には楽なので、いつも個別に追加していたのですが、一括で追加した方が良さそうですね。個別に追加すると追加のたびに再描画されるので、ウィンドウが猛烈に「ちらつく」という問題もありますし。