C#
.NET
読書メモ

現状においてC#のベースを完全に理解できる本のすゝめ


最初に

本記事は以下の本(スラスラわかるC#)にて得た知見のメモと、全体を通して何が得られたのかレビューする内容となっております。

image.png

本の購入を検討中の方はもちろんC#をこれから学びたい・復習したい方の参考になればと思います。

またUnity 2019.1以降は「CSHARP_7_3_OR_NEWER」っていうシンボルを使ってC#7.3が使えるのでお試しあれ。


1章 C#プログラミングを始めよう


所感

第1章ということで、全くの初心者からでもイメージしやすいように、プログラムとは何かを説明したり、内部での処理構造を図解されていました。そこから徐々に掘り下げが行われ、C#や.NETも当然、丁寧に解説されています。それだけではなく、IDE(VS)の使い方もスクショ付きでわかりやすく記述されているため、ワクワクしながらプログラミングの世界に入り込んだ初心者の方が、「手元のPCで早速何か書いてみたい、動かしてみたい」と思った時すぐに手助けしてくれる、そんな章だと感じました。

また、C#のコンストラクターやイベントなどの基本的なメンバや、イテレーターや非同期メソッドのような特殊メソッド、その他単項演算子一通りに関しても説明付きで表にされているため、現役C#プログラマーでもふと忘れた時に見返しやすいと思います。


知見


  • C#は様々なタイプの言語の特徴を備えている「マルチパラダイム」言語である。

  • .NETはC#/VB/F#などの言語間での相互運用や、基礎機能のライブラリや、GCによるメモリ管理の自動化、セキュリティの保証を提供する。

  • MacやLinuxで.NETを使用したとしてもWindowsと同レベルのパフォーマンスや信頼度で動作する。この2つのOSでも必ず動作する機能に絞ったライブラリのことを「.NET Standard」という。


  • 共通中間言語のことをCIL(Common Intermediate Language)、それをマシン語に変換するのが仮想実行環境:VES(Virtual Execution System)である。

  • .NETから標準で用意されているライブラリをBCL(Base Class Library)という。

  • C#7.1では非同期Main、default式。7.2ではprivate protected、参照周りの新機能。7.3では参照周りの新機能、パフォーマンス向上のための新機能が追加された。


2章 手続き


所感

最初のプログラムを書くために必要な基礎知識がコード例と共にしっかりと解説されています。初心者が持ちがちな疑問を、できるだけ解決しながら進められているため、学習中につまづくこともなさそうという印象です。特に型に関して力を入れて解説されているので、他で情報収集をしなくても、この章で必要な基本を押さえることができます。悪例と共に解決法も紹介されていることもあり、私自身も読んでいて土台の知識の補強ができました。また、シフト演算やchecked/uncheckedに関しても触れているので、ある程度C#を書いている方でも読み応えはあるかと思います。


知見


  • outなどの文脈キーワード(contextual keyword)を変数名として使うためには、変数名の前に「@」をつける必要がある。

  • サーバーから情報を取得する時やスクリプト言語と連携する場合など、変数の型情報はdynamic型で動的に解決した方が楽。

  • C#7.0以降は数字と数字の間に「_」を自由に入れることが可能。これによって数値をわかりやすく表現できる。 (int i = 0b1010_1000_1110_1111;)

  • C#7.2以降はさらに0xや0bの直後に「_」を入れることができるようになる。

  • IEEE 754-2008はC#の誕生よりも後にできた規格のため、decimal型の内部表現はIEEE 754-2008と互換性がない。

  • decimal型は仮数の精度が高く(28桁目まで)、指数の幅が小さいため、float/double型へのキャスト不可能。

  • 少数の後ろに「m」か「M」を付けると、decimal型のリテラルと認識される。

  • UTF-16使用時に𩸽などの難読漢字などを収録するため、2文字分の記憶領域で1文字を扱う手法を「サロゲートペア」という。

  • 文字列リテラルに使う"の前に@を付けると、「逐語的文字列リテラル」となり、エスケープシーケンスを展開させず、文字列リテラルを複数行にして書ける。

  • シフト演算によって値を二倍又は半分にできる(余りは切り捨て)。

  • ビットごとの「0/1反転」(補数)を行う演算子として「~」が使われる。

  • オーバーフローをエラーにするか否か選択する手段は二つ。一つはコンパイラ側で検知用のオプションを指定すること。もう一つは「checked/unchecked」を使ってコードの一部分だけ挙動を切り替えてエラー検知を行う方法。checked内でオーバーフローが起きた場合は「OverflowException」が発生する。


3章 データの構造化


所感

配列やクラスの概要と生成時の考え方が図解され、その後に使用方法がコード例と共に紹介されています。ものづくりに例えて「インスタンス」の概念も説明されているため、コードを見た時もそのコードが何をしようとしているのかイメージしやすいと思います。後半には匿名型と、C#7から登場したタプルに関してみっちり解説されています。なんとなくで理解していた機能でしたが、コード例と共に使用事例が多く載っていたり、最新の使用方法が紹介されていたため、私にとって学びの多い章となりました。使い方に困った時にはここを見ればバッチリだと思います。


知見


  • 匿名型は自身のプロパティに、他のクラスが持つ同名のプロパティを初期化用として渡す場合、他のクラスが持つ同名プロパティを使うものとしてプロパティ名を省略できる(例:「new {ID = user.ID, Name = user.Name}」→「new {user.ID, user.Name}」)。

  • 匿名型はコンパイル時に自動的にクラスへと展開される。これによってdynamicを使った動的なプロパティ名の解決も正しく実行できる。ただしタプルでは不可。

  • 匿名型のプロパティはreadonly。

  • タプルのプロパティはwritable。

  • タプルはコンパイル時に自動的にValueTupleという型へ展開される。(例:ValueTuple< string,int >)

  • タプルはクラスメンバとして外部に公開される箇所に使用された場合は、コンパイラに名前がわかるように「TupleElementNames」という属性が付与される。

  • タプルにはdynamicのような仕組みは動作しないことが考えられるため、使えない。使用すると実行時エラーとなる。

  • タプルの分解と同時に、変数を新しく宣言するような分解方法を「分解宣言」という。

  • タプルの分解で得られる値を既存の変数に代入する方法を「分解代入」という。

  • タプルにおいて、分解元のメンバと分解先の変数の型が異なる場合は暗黙的な型変換が行われる。

  • C#7.0以降ではタプルが持つメンバの値を無視(二つ目の値を無視して一つ目と三つ目を使用する等)するために、「値の破棄」(アンダースコアの特別扱い)が導入された。(例:var (a,_,b,_) = (1,3,5,7))

  • タプル間の代入はメンバの宣言位置に基づいて行われる。

  • タプルは入れ子も可能。

  • タプルにおいて、C#7.1以降は変数名の推論ができるようになった。(例:t.xのような書き方)


4章 手続きの構造化


所感

まず最初に、whileやforなどのループや条件分岐について書いてあります。ここではフローチャートの図を用いてあり直感的に理解しやすくなっていました。次に関数についてです。オーバーロードやオプション引数といった機能に関しても余すことなく説明されていました。特にparamsの使い方が曖昧だったため、ここでコード例を見ることができ、とても有難かったです。例外処理に関しても、throwやtry-catch文などの基礎的な使い方の他に.NETが標準で提供する例外クラスのよく出てくるもの一覧が載っています。この一覧は例外が起きた時に参照するのがちょうど良いかと思います。終盤では名前空間について解説されていました。どういった時に使用するべきかが書いてありましたが、初心者の方は最初に第5章を読んでからここを読んだ方が理解しやすいかもしれません。定数(const)もこの章で解説されています。結構ボリュームのある章だと思いますが、基本構文の理解をするためには必読となる章だと思います。


知見


  • paramsを使って、値群に対する一時的な配列の作成を無くし、値群を直接関数へ可変長引数として渡すことができる。

  • 名前付き引数を使って、関数に対する引数を任意の順番で書いたり任意の引数を省略することが可能。(例:Set(SizeX:10,SizeY:30,SizeZ:40); Set(SizeZ:25);

  • C#7.0以降はthrowが式として書けるようになった。ただし、ラムダ式や式形式メンバーの中、null合体演算子、条件演算子といった箇所にしか使えない。

  • 例外は関数の呼び出しを遡る。throwで例外発生したメソッドの呼び出し元に例外処理がなければ、さらにそのメソッドの呼び出し元へと遡る。

  • catchの中でさらにthrow;と書くことで、呼び出し元のメソッドに対しても受け取った例外を再度発生させて処理させることができる。

  • try-catchを用いた例外処理はifステートメントを使用した場合に比べて例外発生時のコストが大きい。そのため慣れてきたらどちらを選んで例外処理を行うべきか検討すると良い。

  • コンパイルオプションでエイリアスをつけることを「外部エイリアス」という。宣言としてはextern aliasをソースファイル中に宣言する。またソースのコンパイル時にcsc /r:User=code.dll Test.csといったようなオプションを追加する。


5〜7章 オブジェクト指向


所感

5章はオブジェクト指向とは何か、クラスや構造体とはどういったものか、この二つは何が違うのかを解説した章です。具体例とクラス図を出しながら説明されているので、わかりやすいかと思います。6章では定数系の話を序盤にしていますが、ここでconstのバージョニング問題を取り上げているため、ある程度C#を触ったプログラマーでも一度確認しておくべきだと思います。そのほかに、コンストラクタ/デストラクタ、最新バージョンのC#に対応したアクセシビリティの種類の解説や、プロパティやpartialの話が登場しています。個人的にはpartialの使い所や、実際にコンパイルされた後の話に関しては知らなかったため、とても勉強になりました。7章では継承やキャストの話が前半に持って来てあり、単なるキャスト(アップキャスト等)、as演算子のキャスト、is演算子のキャストに関して使い分けが紹介されていて面白かったです。そもそもis演算子でキャストが可能になっていたこと自体知りませんでした。後半では仮想メソッドやインターフェース等を用いた多態性の話や、キャストの可否結果を用いたswitchなどのパターンマッチングに関する話が登場しました。when句が追加されたことでよりコードの可読性が上がったなと言う印象です。また本の中ではis演算子を用いた変数作成をした場合のステートメント別スコープの範囲と言う深いところまで検証と解説がされています。さすがとしか言いようがない内容の充実さですね。


知見


  • 構造体を選ぶ基準として、データのサイズが16バイト以下であり、絶対に継承しないことがわかっていて「変数への代入がコピーを生成することを許容できる」場合のみが望ましい。


  • 「private protected」は同一プロジェクト内のクラス内部、且つ派生クラスの内部からのみアクセス可能。

  • 一応リフレクションを使うことでバックフィールドを見ることはできる。

  • 静的コンストラクタで静的変数の初期化が行える。これは対象のクラスが最初に参照された際に一度だけ呼び出される。

  • 静的クラスでは静的メンバーしか定義できない。

  • C#6.0以降で使える「using static」で静的メンバのクラス名省略をすることができる。


  • 「partial」をつけた部分メソッドは、①必ずpartialクラス内にあり、②private且つvoidとするが、③引数(out以外)は利用可能である。④staticメソッドでもインスタンスメソッドでもpartialにできる。

  • partialメソッドに実装が定義されていない場合、呼び出してもコンパイル後の実行ファイルからは消えている。これによってコストがかかるのを避けている。

  • as演算子は型変換が失敗した時はnullを返す。普通のキャスト式であれば例外を返す。C#7.0以降からはis演算子によるキャスト(式:変数名 is 型名 変数名)も可能。この場合、値がnullである変数にis演算子を使うとfalseが返ってきて、問題なければ宣言した変数名に値が入る。(例:if(obj is string str){ int num = str.Length; }

  • is演算子を式として使うことも可能。(例:var num = obj is string str ? str.Length : 0;

  • ifの条件式でis演算子を用いて変数を宣言した場合のスコープは他と違って、if文のステートメント後でもその変数にアクセスが可能。

  • 派生クラスに基底クラスが持つメンバーと同名のものを作成すると基底クラスのメンバーが隠蔽される。隠蔽を意図的に行いたい場合はメソッドに「new」修飾子をつける必要がある(つけないと警告がでる)。(例:public new void Hoge() )

  • C#7.0以降はswitch文のcaseに「値が指定された型にキャストできるかどうか」(例:case 型名 変数名(キャストした結果がここに入る) )と、when句の後に条件式を書くことができるようになった。


8章 第一級市民化


所感

オーバーロード等を用いてユーザー定義型と組み込み型を同列に扱うための方法が丁寧に解説されています。特にオーバーロードが可能な演算子と、オーバーロード不可の演算子に対する代替手段が表にされているため、自身で演算子オーバーロードを実装する必要がある場合にすぐ見返すことができてとても便利です。そのほかに、?:演算子を使用できるようにするには何をしたらいいか、条件演算子?:が使用できるのであれば&&、||演算子をオーバーロードしなくてもいいのは何故なのかが説明されていました。ここは少し難しいとは思いますが読み解けば確実にレベルアップできます。コレクション初期化子、インデクサー定義においてもどのような挙動と実装の流れになるのか、わかりやすい利用例が提示されているため、ここはすんなり理解できるかなという印象です。


知見


  • ユーザー定義型を組み込み型と区別しないように扱うことを指して「すべての型が第一級市民(first-class citizen)である」と言う言い方をする。

  • コレクション初期化子を使えるユーザー定義型の条件として、①IEnumerableインターフェイスを実装済みで、②Addメソッドを持っている、と言う必要がある。

  • インデックス初期化子はAddメソッドを持たなくてもインデクサー定義があればOK。

  • C#6.0以前は拡張メソッドにてAddを追加してもコレクション初期化子が使用できなかったが、6.0以降は可能に。

  • インデクサーはILだとパラメータ付きのプロパティとして扱われる。IL内だけの話ならパラメータ付きプロパティを定義可能だが、C#で書く場合にはコレクション型のプロパティが推奨されている。他の言語で定義されているパラメータ付きプロパティを使用する場合には、get_プロパティ名/set_プロパティ名と言うメソッドに見える。


9章 関数中心の機能


所感

まずデリゲート周りについての話から進められていきます。ここで初心者の方はC#が持つイベント系統の機能について詳しく学べるかなと思います。付随して、ローカル関数でラムダ式、イテレータやジェネリクスでのパターンにおける使用例を挙げてくれているため、実際にコードを書くときになった場合に手元で書き方を確認することができます。個人的にこの箇所は理解不足だったため、今後も何度か読み直したいと思いました。その後でイベント構文の話をして、より簡単にイベント周りの実装が行えるように提示しています。具体的にどのような仕組みになっているかまでは知らなかったので勉強になりました。拡張メソッドを紹介している箇所では、静的メソッドと拡張メソッドの違いと拡張メソッドのルールについて触れられています。それぞれにサンプルコードがあるので直感的に理解しやすく感じました。


知見


  • C#1.1以前ではデリゲート利用時にnewが必要だった。

  • EventHandlerは「イベント処理」に使用。Predicateはbool型を返す1パラメータのデリゲート。

  • ラムダ式は文脈からパラメータの型を推論できる場合は型を省略可能。(例:private int Hoge(Func<int,int> func){ return func(5); }と言うメソッドが定義されているとしてvar num = Hoge(x => x + x); とした場合、型推論としてxはint型となる。)

  • C#6以降で使える式形式メンバーにて、int X => 0;と書いた場合はgetアクセサーしか持たないプロパティとなる。

  • ローカル関数と匿名関数の違いとして、①ローカル関数は関数メンバーの直下にしか書けず、②再帰呼び出しが容易に書けて、③イテレーターやジェネリックにできる。また④引数の規定値を持つことができる。匿名関数は(LINQのような)一行で表すことのできる式を埋め込むなど簡単なものには使えるが、関数としての機能をフルには使えない。

  • ローカル関数は使用箇所のあとで宣言してもOK。

  • イベント構文で記述したイベントはクラス内部からは丸括弧を使った呼び出しが可能で、クラス外部からは追加と削除のみ可能。Add/Removeメソッド相当のアクセサーが生成される。

  • イベント構文使用時にはEventHandler型の利用が推奨される。

  • 拡張メソッドを使うことで①語順がわかりやすくなり、②インターフェイスやクラスとは独立して実装できるようになる。

  • 拡張メソッドはusingディレクティブで参照した名前空間の中にある全ての静的クラスの中からシグネチャが一致するメソッドを探して呼び出されている。


10章 メモリ管理


所感

まずスタック/ヒープの概要と、そこに対して値型と参照型がどのように振り分けられるか、そしてデータの格納先によってどのような特徴があるかを順序立てて図を用い説明してくれています。そこから参照渡しとはどうやって行うのか、それにちょうどいい機能はどんなものがあるかをC#の最新バージョンから紹介されていました。特に参照戻り値と参照ローカル変数、出力引数の変数宣言は初見だったので面白かったです。後半ではnull許容型に対する演算の結果表がとても詳しく書かれています。特にbool?型に対しての論理演算ではどのような結果になるかもページ半分をとって見やすい表になっています。usingステートメントについては確か一度勉強したことがあるはずだったんですが、改めて解説を見て見ると、こういう時に使うものだったかな、という風にうろ覚えだったのを自覚したのでじっくり復習させて頂きました。


知見


  • ヒープは①データがあちこちから参照されてスコープがはっきりしない場合と、②実行時にしかサイズが確定しない場合と、③必要サイズがかなり大きい場合に、利用する。


  • ボックス化(boxing)は値型のコピーをヒープ上に作って、object型の変数に渡す処理のこと。逆をボックス化解除(unboxing)と呼ぶ。ただし可能な限り値型は値型のままで利用すべき。

  • C#7以降は参照戻り値とその戻り値用の参照ローカル変数が導入された。パフォーマンスやリソースを意識する必要がある場合に使用することで、大幅な性能向上が見込める。

  • 参照ローカル変数とは、ローカル変数でも参照渡しを実現できる構文のこと。(例:ref 型名 変数名 = ref 宣言済みの変数名または参照戻り値を返す関数の呼び出し;

  • C#7以降は出力引数(out演算子使用)を引数の変数宣言を()内で行えるようになった。(例:Hoge(str,out var num);


  • Nullable<T>構造体はHasValueというbool型のプロパティとValueというT型のプロパティを持っている。Valueは有効な値を返すがHasValueがfalse(つまりnull)の場合は例外InvalidOperationExceptionを投げる。

  • ファイル等のリソース破棄の手間を軽減する構文としてusingステートメントというものがある。(例:using(Resource r = new Resource()){ リソースに対する操作 } で 最後に必ずDispose()が行われる。)

  • usingステートメントを使う場合はリソース管理用クラスにIDisposableが実装されている必要がある。


11章 ジェネリクス


所感

まず初心者の方にもわかりやすいように、ジェネリクスが何故必要となるのかをNGコードと合わせて紹介してくれています。ジェネリックなクラスやメソッドを定義するに当たって、型パラメータに対する制約条件もいつも通り表になっているため、安定の見やすさです。後半ではC#をある程度使っているプログラマーの方でも引っかかりがちな共変性/反変性の二種類をできるだけ噛み砕いてわかりやすく説明しようしてくれています。また、その二種類を実現するためのin/out修飾子の使い方もサンプルコードがあるため、ギリギリ理解できるかなーというところでしょうか。難しくてわからなくても一旦飛ばしてまた慣れてきた頃に読み返すのがいいかもしれません。


知見


  • ジェネリクスを用いた結果、依存性/相関性が低い状態のことを「直交性が高い」という。

  • 参照型を一切含まない型のことをアンマネージド型と呼ぶ。

  • ジェネリックなクラスやメソッドは、構築前の状態をオープン、構築後の状態をクローズと呼ぶ。

  • 共変性のためにはout修飾子を使い、反変性のためにはin修飾子を使用する。

  • 型引数が値難となる場合は共変性/反変性は使えない。「値型は不変である」という。


12章 データ処理


所感

この章ではイテレータとLINQの説明がメインになっていました。特に混乱しがちなIEnumerableインターフェイスとIEnumeratorインターフェイスの二つについて中身の実装を見せつつ明確に違いを教えてくれているので助かります。LINQに関してはまず要素ごとに細かい手順に分解して、その後一つ一つどんな句を使って解決していくか紹介されているため、LINQの使い方に困った時にも役立つ内容かと思います。ただ個人的にはGroupByの説明が少し物足りないと感じたので【C#入門】LINQのGroupByでグループ化する(OrderByも解説)と言うサイトで補強を行いました。最後にIEnumerable<T>とIQueryable<T>の違いと使い分けに対する説明は、この二つ自体ほとんど使ったことがなかったため読んでていてとても面白かったです。もし使う機会があれば是非色々試してみたいと思いました。


知見


  • IEnumerableインターフェイス自体はIEnumeratorインターフェイスを返すメソッドを一つ持つだけ。

  • yield returnステートメントを含んだブロックのことを「イテレーターブロック」という。

  • 処理の合間にThread.Sleep(1000)を入れて複数回に分けて列挙した後に結果表示する場合、①全要素分のメモリ領域を事前に確保する必要がなく、②無限に続くデータ列も作れる。

  • LINQに対応したライブラリのことをLINQプロバイダーと呼ぶ。代表例で「LINQ to Objects」。

  • C#コンパイラはクエリ式をメソッド呼び出しへ機械的に置き換えている。

  • メソッド形式内などで現れる、コンパイラが自動生成する変数のことを透過識別子と呼ぶ。この識別子は名前衝突がなされないように通常のC#では受け付けられない記号入りの変数名となっている。

  • クエリ式は、select句またはgroup by句で終わる。

  • let句を使うことでクエリ式中で計算した値を変数に格納できる。let句からはSelectメソッドが生成され、その中に透過識別子が登場する。(書き方例:let TotalNum = user.TestNum1 + user.TestNum2 )

  • IEnumerable<T>インターフェイスがラムダ式を普通にデリゲートとして受け取るのに対し、IQueryable<T>インターフェイスはラムダ式を式ツリーとして受け取る。

  • DBやWeb APIなど外部システムからデータを取ってくる場合、IEnumerable<T>インターフェイスが外部システムにデータ取得依頼を出し、貰ったデータ全件をプログラム中で加工するのに対し、IQueryable<T>インターフェイスはSQL文を生成した後に外部システムにデータの加工までお願いしてから加工済みのデータを取得する。通常は後者の方が性能が良い。


13章 非同期処理


所感

多くの人が理解に時間がかりがちな非同期処理について、マルチスレッドの解説からTaskクラス等の使い方や排他ロックについてまで、一通り丁寧に解説しています。C#のバージョンアップによってできるようになった細かな機能の違いや書き方に関しても解説されているのでC#の最新versionに追いつけていない人でも読み直すことで最新の書き方が身につきます。私自身も非同期処理に関してはUnityでのコルーチンを使える程度の知識だったので、async/awaitの使い方に関してはほぼ初心者レベルでした。この章を読んだことで非同期処理用の機能がどのように動いているか、パフォーマンスとしてはどうなるのか、排他ロックをかけない場合にどのような事態になり得て、どのようにすれば回避できるのか一通りの知識が身につきました。苦手意識がある人も、図と共にわかりやすく説明されているのでぜひご一読ください。


知見



  • ThreadはOSが提供するスレッド機能そのものに近い低級なクラス。ThreadPoolはあらかじめ用意してあるスレッドをうまく使い回す仕組み(スレッドプール)を提供する。Taskはスレッドプール上での処理をC#で使いやすい形として提供する。Parallelは同じ処理を複数のスレッドで並列して行いたい場合などに使う。

  • C#6.0以降からcatch句やfinally句の中でもawaitが使える。

  • 非同期メソッドの戻り値は、①非同期の完了は待つ必要ない場合にvoid、②完了を待つ必要がある場合に非同期メソッドビルダー(Task、Task<T>、ValueTask<T>など)を実装した型である必要がある(C#6まではvoidかTaskかTask<T>である必要があった)。

  • ほんの一部分しか非同期処理が行われない場合にTask(参照型)のインスタンスを生成するとコストが大きい。ここでValueTask構造体(値型)を使うことで必要に応じて内部でTaskのインスタンスが作られるようになり、同期的処理がメインのメソッドのパフォーマンスが大幅に向上する。

  • C#7から非同期メソッドビルダーを実装した型(一般化非同期戻り値型)であれば、そのインスタンスを非同期メソッドの戻り値として使えるようになった。ただ、この型を独自に定義することはほぼない。

  • 非同期メソッドの完了を待つ場合、返り値がない場合はTaskを用いる。(例:async Task Hoge()

  • TaskクラスにはWhenAllメソッド(全てのタスクが完了した時に完了するタスクを作成する)や、Runメソッド(引数として渡したデリゲートを別スレッドで実行するタスクを作成する)のような便利機能が多数用意されている。

  • 戻り値が欲しい場合はTask<T>を使う。

  • C#7.1以降はMain関数の戻り値型にTaskとTask<int>が使えるようになった。

  • asyncを付けたラムダ式を非同期ラムダ式と呼ぶ。

  • Parallelクラスのforメソッドに渡した処理は複数のスレッドで同時実行される。(例:Parallel.For(ラムダ式など) )

  • 複数のスレッドが同時に行ってはいけない一連の処理が記述された部分のことをクリティカルセクションと呼ぶ。

  • 排他ロックをかけるためにMonitorクラスを使うことで静的メソッドである、ロック取得のためのTryEnterメソッドと、ロック解放のためのExitメソッドが使える。

  • 鍵をかける対象となるオブジェクトのことを同期オブジェクトと呼ぶ。


  • lockステートメントを使うことで、コンパイラが自動的にMonitorクラスを用いた排他制御用のコードを生成してくれる。(例:lock(同期オブジェクト){ クリティカルセクション }


最後に

この本を読むことで、C#に関する一通りの実践的な知識を学ぶことが可能だと思います。プログラム入門者から中級者、最新のC#にまだ追いついていない人へ強くオススメしたい良書です。既に何名かの初心者にこの本をオススメしておりますが、総じて好評価の感想が返ってきています。私が(おこがましいかもしれませんが)初心者寄りの中級者レベルだとしても、この本を読んでこれだけの知見を得られたので、C#をある程度使ったことがある人にも是非手にとって頂きたいですね。

五十嵐 祐貴さん、岩永 信之さん、執筆お疲れ様でした。献本して頂けて、とても光栄です。この本は何度も読み返すことになると思います。このような良書を読むことができて本当に感謝しかありません。有難うございました。