C#での、正しいマルチスレッドプログラムの書き方を求めて(2011年11月版)
「C#におけるマルチスレッドプログラミングの正しい作法が知りたい」
そんなとき、やっぱりたよりになるのはmsdnだよねということで、msdnライブラリから、意外と散らばっているマルチスレッド関連ページをかき集めて、参考になりそうな資料を抜粋し、一覧にしたのがこのエントリです。
この記事は2009年の記事をベースに、一覧の内容を大幅にアップデートしたものです。内容は新しくなり、量も増えました。
丁寧な解説が良い
集めた資料にはマルチスレッド用のデザインパターンやガイドライン、 基礎的な用語の解説などが充実しており、とても参考になります。 クラスの解説だけでなく、 こういう場合はどれを使った方がよいという指針が明らかにされていて頼もしい限りです。
一つ一つ読むもよし、また、なんとなく興味を惹かれるタイトルのページを開いてみるのも面白いと思います。
C#のアクセス修飾子を書かなかった場合に関して
背景
C#のアクセス修飾子(public, private, internal, protected など)については、C#の基本的事項として、入門書や入門者向けホームページにもほぼ間違いなく記載されている基本的な事項です。
しかし、(特にホームページで)publicやprivateを付けるとどうなるかの解説はほとんどの記事に含まれていますが、もし、何も付けなかったらどうなるかが書かれていないことがよく見受けられます。
また、それらはたいていメソッドや、フィールド、プロパティなど、クラス内のメンバに関してであり、クラスにつけるprivateやpublicについてどうなるかについてもあまり記述がありません。
今回は、以上の2点が今ひとつ分からなかったため、それらを解決すべく、C#のアクセス修飾子(access modifier)についてC#の仕様書(C# Language Specification, 英語, 約500ページ)のアクセス修飾子に関する部分を読んでみましたC#の仕様書は、英語ですが簡単にダウンロードできます今回は、読んで私が先ほどの分からなかった点のうち、特に何も付けなかった場合に関する部分について理解したことをメモしておきます。詳細は直接仕様書へどうぞ。
メンバ(Members)とは
C#のコードには、名前空間の中にクラス、クラスの中にメソッドのように、階層構造があります。この階層構造があるということが重要です。そして、その最上位がグローバル名前空間(Global namespace)です。そして、各階層名前空間やクラスなどのすぐ下の階層にある要素クラスやメソッドなどのことをメンバ(Members)と呼びます。
ここではそれぞれの要素が持ちうるメンバーを示します。また、型(type)とは、構造体(struct)、列挙体(enumeration)、クラス(class)などを指しますが、話を省略するため、型の代表としてクラスを利用して説明します。
- グローバル名前空間
- 名前空間
- クラス
- 名前空間
- クラス
- クラス
- クラス
- 定数
- フィールド
- プロパティ
- メソッド
- イベント
- インデクサ
- 演算子
以降、名前空間AのメンバにクラスBがあるとき、名前空間Aを、クラスBの親メンバ、クラスBを名前空間Aの子メンバと呼ぶことで、わかりやすくしたいと思います。つまり、「この要素をメンバとして持つ要素」を「親メンバ」と呼びます。
5つのアクセシビリティ(Declared accessibility)
ここでは、まず要素の持ちうる5種類のアクセシビリティを紹介します。要素に対してこの5つ以外のアクセシビリティが与えられることはありません。必ず要素はいずれかのアクセシビリティを持ちます。あくまでアクセス修飾子と区別するために、すべて大文字にしてあります。
- PUBLIC
アクセスは「制限されない」("access not limited") - PROTECTED
アクセスは、「親メンバ内部」および「親メンバクラスを継承した型の内部」に制限される("access limited to the containing class or types derived from the containing class") - INTERNAL
アクセスは、「この要素が含まれるプログラム(アセンブリ, .exe, .dll)」に制限される("access limited to this program") - PROTECTED INTERNAL
アクセスは、「この要素が含まれるプログラム」および「親メンバクラスを継承した型」に制限される("access limited to this program or types derived from the containing class") - PRIVATE
アクセスは、「親メンバ」に制限される"access limited to the containing type"
あとは、それぞれの要素がどのアクセシビリティを持つかが問題です。
アクセシビリティの決定方法
ここでは、どのアクセシビリティになるかがどう決まるかを説明します。基本は簡単です。
- public, protected, internal, protected internal, privateのアクセス修飾子があるばあいは、それぞれPUBLIC, PROTECTED, INTERNAL, PROTECTED INTERNAL, PRIVATEのアクセシビリティとなる。
-
アクセス修飾子が存在しない場合は、それぞれのデフォルトアクセシビリティとなる。ここで、それぞれの要素のデフォルトアクシビリティは次のように定義される。ただし、要素のデフォルトアクセシビリティが、その要素の親メンバのアクセシビリティとは無関係に事前に決められていることに注意。
- 名前空間
PUBLIC - 型(入れ子にされていないクラス、構造体など)
INTERNAL - クラスの子メンバ(メソッド、入れ子にされた型など)
PRIVATE - 構造体の子メンバ
PRIVATE - インターフェイス
PUBLIC - 列挙型
PUBLIC
- 名前空間
以上を使うことで、すでに記述されているC#のコードのアクセシビリティを判断できると思います。実は、これ自体だけでは、結局正確にどこからアクセス可能かは判断できません。それに関しては、あまりに量が多いのでもうあきらめます。
ところで、これだけでは、自分でコードを記述するときに、どのようなアクセス修飾子を記述可能なのかは分かりません。それについては次です。
要素に付けて良いアクセス修飾子(C#言語仕様 3.5.1節より)
アクセス修飾子(public, protected, internal, protected internal, private)は、付けて良い場所と、付けては行けない場所があります。付けていけない場所に付けると、「名前空間で定義された要素は明示的に private、protected、または protected internal に宣言することはできません」のようなコンパイルエラーが発生してしまいます。以下、それぞれの要素に付けられるアクセス修飾子をまとめました。
- 名前空間
付けられない。 - 型(入れ子にされていないクラス、構造体など)
public、internal - クラスの子メンバ(メソッド、入れ子にされた型など)
public、protected、internal、protected internal、private - 構造体の子メンバ
public、internal、private - インターフェイス
付けられない。 - 列挙型
付けられない。
まとめ
以上、メモでしたが、このエントリのタイトル「C#のアクセス修飾子を書かなかった場合に関して」、つまり、public, protected, internal, protected internal, privateのいずれもしていなかったときどうなるかは、次のようにまとめられます。
- 名前空間
PUBLIC - 型(入れ子にされていないクラス、構造体など)
INTERNAL - クラスの子メンバ(メソッド、入れ子にされた型など)
PRIVATE - 構造体の子メンバ
PRIVATE - インターフェイス
PUBLIC - 列挙型
PUBLIC
見ての通り、前述した、「デフォルトアクセシビリティ」になる、ということですね。
感想
本当に困ったら、言語仕様を読むのが一番よさそうですね。ただ、次に紹介するmsdnには、同じことが優しく書いてあったりするので、そちらをまず参考にすることをおすすめします。
参考文献
- C# Language Specification Version 3.0(英語)
- 3.4 Members
- 3.5.1 Declared accessibility
- 3.5.2 Accessibility domains
- 10.3 Class members
- 10.3.5 Access modifires
- C# リファレンス(msdn)
- C# プログラミングガイド(msdn)
書籍で読みたいなら、定番の「Programming C#」もしくは、その訳著「プログラミング C#」がおすすめ。msdnで十分だとは思うけど、本がいい人向け。
おまけ
Programming C# 4.0 が Programming C# 第6版 として2010年4月15日(@amazon)に発売されます。もちろん、英語ですが、これの日本語版が出るのはだいぶ先と思われます。C# 4.0の増えた部分が結構多いので、チェックしてみては。
C#での、正しいマルチスレッドプログラムの書き方を求めて
注意:.NET Framework 4、Visual Studio 2010に対応してアップデートした記事はこちら→「C#での、正しいマルチスレッドプログラムの書き方を求めて(2011年11月版)」
C#におけるマルチスレッドプログラムの作成方法は、たくさんのホームページで紹介されています。しかし、それらは正しく動いたとしても、それがC#や.NET Frameworkを作成した人々の期待したコードであるかどうかは残念ながら、コードを見るだけでは分かりません。生意気なこと言ってすいません
また、BackgroundWorkerという、簡単に別スレッドを作成してメソッドを実行する方法も用意されてはいますが、それで満足していいのかという欲求もあります。より高度なスレッドの扱い方を会得したい。
そんなとき、やはり頼るべきはMicrosoft謹製 msdnライブラリでしょう。
しかし、実際にmsdnライブラリでマルチスレッドプログラミングついて調べていると、リンクが散らばっていて、どこを見ればいいのか分かりません。
そこで、msdn内のマルチスレッドに関するページをまとめてみました。msdnは重く、検索に時間がかかるので、このページをブックマークしておくと楽だと思います。
Visual Studio 2008 を Eclipseライクなフォント・配色にしてみる
そう思うのは、おそらくJavaで利用していたEclipseの外観に見慣れていたからに違いないということで、Visual Studio のフォントと配色を変更して、Eclipseライクにしようというのが今回の目標です。
では、実際にどうやったかというと、
設定はすべて「ツール(T)>オプション...(O)」から呼び出したオブション画面中の「環境>フォントおよび色」で行います。
まず、フォントについてです。「フォントおよび色」の画面を表示した状態で、「フォント」を「Courier New」にします。これだけで、ものすごくEclipseっぽくなります。
配色は完全に同じにということは設定の種類による制限上不可能なのですが、その制限の中で見やすくしてみた結果を書いてみます。
以下、設定の上から順、C#向けです。(※カスタム(63,95,191)という表記は、色の選択でカスタムから色の作成を選んで、赤63,緑95,青191にするという意味です。)
- XML ドキュメント コメント → 前景色:カスタム(63,95,191)
- XML ドキュメント タグ → 前景色:カスタム(127,159,191),太字
- キーワード → 前景色:カスタム(127,0,85),太字
- コメント → 前景色:カスタム(63,127,95)
- コンパイル エラー → 前景色:赤
- ユーザー キーワード → 前景色:自動
- ユーザー タイプ → 前景色:カスタム(0,0,192),太字
- ユーザー タイプ(インターフェース) → 前景色:自動
- ユーザー タイプ(デリゲート) → 前景色:自動
- ユーザー タイプ(値の型) → 前景色:自動
- ユーザー タイプ(列挙型) → 前景色:自動
- 文字列 → 前景色:カスタム(0,0,192)
- 文字列(C# @ Verbatim) → 前景色:カスタム(0,0,192)
以上です。
これで、あとは自分好みに変更してみてください。
HTTPヘッダ Connection : close
今回は、HTTPヘッダにConnection : close を設定したかったので、Connectionプロパティを使うのかなぁと思っていました。
それで、実行してみると、
「このプロパティを使用して、Keep-Alive および Close を設定することはできません。」
というエラーが。 はぁ、そうなんですか、じゃぁいつ使うんですか?って思っちゃいます・・・
それはいいとして、じゃぁ、どうすればいいのかと。
ちょっと調べると、HttpWebRequestクラスには、KeepAliveプロパティというのがあるみたいでした。
ということで、KeepAlive = false にすると、ConnectionがKeep-Aliveじゃなくなって、Closeになるのかな・・・と。とっても適当です(笑)
fiddlerで調べればいいんですけどね。ちょとメモ程度に書いておきます。