書評:「究極のC#プログラミング 新スタイルによる実践的コーディング」のまとめ
「究極のC#プログラミング 新スタイルによる実践的コーディング」を読んだので、まとめてみました。 自分用のメモなので、適当にまとめちゃってますが。
3.新しい繰り返しスタイル
yield return
yield return 文
とyield break 文
反復子ブロックと呼ばれている。
class Range { private int from, to; public IEnumerator<int> GetEnumerator() { for (int i = from; i <= to; i++) yield return i; } public Range(int from, int to) { this.from = from; this.to = to; } } class Program { static void Main(string[] args) { foreach (var i in new Range(0, 9)) { Console.Write("{0}", i); } } }
- 反復子ブロックで意識すること
- 反復子ブロックはすぐには実行されない
- 実行されるのは、foreach文で列挙が開始された後
- 反復子ブロック内で
yield return 文
が実行されると、その引数の値がforeach文に渡り、1回実行される - foreach文に指定された実行文(上だと
Console.Write
)の実行が終わると、反復子ブロック内の続きが実行される。
5.null許容型
null許容型とは
- 値型でもnullを保持できるようにする。
- 値型の型名の後ろに
?
を付与するとnull許容型になる
private int? num
null許容型ができた背景
- 参照型と値型が同じように扱えるため。
- ただ、すべての状況において、値型にnullを許容してしまうと、実行速度低下や必要メモリ増加の悪影響が出る。
- そのため、nullを許容したい場合だけに限定されることが可能。
- 逆の言い方をすると、nullになることが絶対にありえない変数の型には使うべきではない。
6.ラムダ式(全編)
ラムダ式は上位スコープにアクセス可能
static void Main(String[] args) { string message = "hello world"; var action = new Action(() => { Console.WriteLine(message); }); action(); }
- 必要とされるあらゆる情報を引数経由で渡さずに済むので、引数の肥大化を防ぐ
static Action CreateAction() { string message = "Hello World"; return () => { Console.WriteLine(message); }; } static void Main(String[] args) { var action = CreateAction(); action(); }
ラムダ式で継承を置き換える
ラムダ式に置き換えた利点としては、ソースコードに書き込む文字数が減り、楽ができ、間違いが混入する可能性も減る。
実際のラムダ式で置き換えたコードは、以下の通り。
class Person { public Person(Action sayMyName) { SayMyName = sayMyName; } public Action SayMyName { get; } public static Person createStringNamePerson(string name) { return new Person( () => Console.WriteLine(name) ); } public static Person createCharNamePerson(char name) { return new Person( () => Console.WriteLine(name) ); } } class Program { static void Main(string[] args) { Person[] persons = { Person.createCharNamePerson('L'), Person.createStringNamePerson("サンプル 太郎"), }; Array.ForEach(persons, person => person.SayMyName() ); } }
8. 部分クラスと静的クラス
部分クラス
部分クラスとは
- クラス・構造体・インターフェースの宣言を複数のファイル等に分割できる
メリット
- フレームワークによって自動生成されるコードとプログラマーが記述するコードをファイル分割できる。
- 自動生成されるコードは、プログラマーが直接修正すると、危険なので、容易に書き換えられないようにすることで安全性が高まる。
- 既存のソースコードを書き換えることなく、機能強化を実施できるため。
静的クラス
- デザインパターンでいうところの
シングルトンパターン
と同じ。 - クラス宣言の際に、
static
キーワードを付けるだけ。 - いわゆる
ユーティリティクラス
とかで使われている - C#3.0で上記の専用の構文が追加された経緯として、特殊なクラスの使い方ではなく、頻出する典型的な使い方に変化。
11. フレンドアセンブリ
12.varによる変数宣言とコレクション初期化子
varキーワード
- 「暗黙的に型指定されるローカル変数」を宣言するためのキーワード
- varキーワードを付与する場合は、必ず変数宣言時に初期化する必要あり。
- varキーワードの型は、常に同じなので、途中で入れ替えることは不可(宣言時が
int
で、string
を代入できない)
varキーワードを使う意図
- クラス名が極端に長すぎてソースコードの読みやすさを損なっている場合
- 同じ型名が2回書かれている場合
- newを使わない初期化で使うべきかは微妙なところ。
verキーワードが使用できない場面
verキーワードを活用できる場面
13.自動実装と自動定義
自動実装プロパティ
通常のプロパティ定義
class SomeClass1 { private int a; public int A { get { return a; } set { a = value; } } }
自動実装されるプロパティ定義
class SomeClass2 { public int A { get; set; } }
- 自動実装プロパティは、常にgetアクセサとsetアクセサの双方が必要。
オブジェクト初期化子
オブジェクトのフィールド・プロパティを初期化する手段
- フィールドの宣言時に初期値を指定
- コンストラクタで書き込む
- オブジェクト初期化子を使う
オブジェクト初期化子の本質
- private /readonlyなフィールドでは初期化できない
- オブジェクト初期化子が、インスタンス作成中に実行されず、できてから実行されるため。
- ただ、コレクションはreadonlyでも初期化子は利用可能。
14.拡張メソッド
概要
- 既に存在するクラスに対して、そのクラスを変更することなく、メソッドを追加できる機能。
- クラスを変更することなくということは、コンパイル済みのバイナリーを変更することなく追加できること。を意味する。
- シールクラス(sealed)を拡張することも可能。
注意点
- アクセス制御
名前 | public | protected | private |
---|---|---|---|
部分クラス | ○ | ○ | ○ |
継承 | ○ | ○ | × |
拡張メソッド | ○ | × | × |
拡張メソッドを使用すべきとき
- 可能であれば拡張メソッドは使わないほうがいい。
- 既存のクラスライブラリに対して、「このメソッドがあれば便利」というような状況の場合に使用する。
- 例えば
Datetime
型に対して、月末日を取得するメソッドを用意する場合など。
15.LINQとクエリ式
LINQのメリット
- 簡潔で読みやすい(特に複数の条件をフィルと処理する場合)
- 強力なフィルタ処理、並び替え、グループ化機能を最小限のアプリケーションコードで実現
- ほとんど変更せずに、他のデータソースに移植できる
Parallel LINQ
を用いると、クエリを並行して実行可能
LINQを使ううえでの注意点
- クエリ対象のコレクションの中身が変化しても、クエリオブジェクトを作り直す必要はない。
- 逆に、ある瞬間のクエリ結果を保存しておきたければ、クエリオブジェクトを即座に列挙しておく必要あり。
- どれほど膨大なデータがヒットするクエリであろうと、クエリオブジェクトを作成するだけなら、ほとんど時間はかからないし、メモリも消費しない。
- どれほど膨大なデータがヒットするクエリであろうと、単にそれらを列挙するだけならほとんどメモリは消費しない。