メソッドチェーン
代表例はLINQが挙げられます。
var result =
items
.Where(x => x.IsActive)
.Select(x => x.Value)
.OrderBy(x => x)
.Take(10)
.ToList();
この LINQ のコードは、
コンテナ系の items を対象に
- Where で条件に合う要素だけを絞り込み
- Select で必要な項目を取り出し
- OrderBy で並べ替え
- Take で先頭から n 件を抽出し
- ToList でコレクション化
その結果を result に代入しています。
メソッドチェーンを自前で書くとこんな感じになります。
public class Builder
{
public Builder StepA()
{
// 何か処理をしたつもり
return this; // ★ 自分自身を返す
}
public Builder StepB()
{
// 何か別の処理をしたつもり
return this; // ★ 自分自身を返す
}
}
StepAもStepBも戻り値でthisを返しています。
インタンスが返ることで「.」でつなげることが出来る仕掛けです。
var builder = new Builder();
builder
.StepA()
.StepB();
具体的な処理の実装は、
引数にデリゲートを取り、
そのデリゲートをラムダ式で渡すことで、
メソッドチェーンとして書けるようになります。
public class Builder
{
public Builder Do(Action action)
{
action?.Invoke();
return this; // 自分自身を返す
}
}
使う側のコード
var builder = new Builder();
builder
.Do(() => { /* 何か処理 */ })
.Do(() => { /* 何か別の処理 */ });
コードブロック
素のコードブロックはスコープを作るための構文と考えられます。
{
var temp = Compute();
Use(temp);
}
// temp はここでは見えない
一般的にはifやusing、try-catch構文などに使う物であり、
素の状態では使うことは少ないですが、あえて意味を考えると
- 変数の寿命を限定できる
- 名前の衝突を防げる
- 「ここだけの一時処理」を明示できる
などがあげられます。
ラムダ式
ラムダ式は、デリゲート(またはデリゲート互換の型)を生成するための
無名関数を記述する構文です。
式タイプ
x => x + 1
引数はx、戻り値はx + 1
1つのメソッドを呼び出すだけのコードなどでよく使います。
コードブロックタイプ
x =>
{
var y = x + 1;
return y * 2;
}
{}の中は普通のコードブロックで、変数を持てます。
また、returnで戻り値を返すことも出来ます。
Actionタイプのデリゲート
Action a = () => Console.WriteLine("Hello");
// 実行
a();
Actionは戻り値なし
Funcタイプのデリゲート
Func<string, int> parse = s => int.Parse(s);
// 実行
int value = parse("123"); // 123
Funcは戻り値あり
具体例
処理時間を計測するコードは、一般的に次のような形になります。
using System.Diagnostics;
~ 省略 ~
var sw = Stopwatch.StartNew();
// 計測したい処理をここに書く
sw.Stop();
Console.WriteLine($"Elapsed: {sw.ElapsedMilliseconds} ms");
この処理をデリゲートとして切り出すと、以下のようになります。
処理時間を計測するデリゲート(使われる側)
using System.Diagnostics;
static void Measure(Action action)
{
var sw = Stopwatch.StartNew();
action(); // 渡された処理を実行
sw.Stop();
Console.WriteLine($"Elapsed: {sw.ElapsedMilliseconds} ms");
}
処理時間を計測したい処理側のラムダ式(使う側)
Measure(() =>
{
// 計測したい処理を書く場所
});
このように、Stopwatch を使った計測処理を
デリゲートとして切り出すことで、
- 毎回同じ計測コードを書く必要がなくなり
- 計測したい処理だけをラムダ式として渡せるようになります
結果として、処理時間の計測を
デリゲート + ラムダ式 という構文に
置き換えることができます。
オブジェクト初期化子
class Person
{
public string Name { get; set; }
public int Age { get; set; }
}
var p = new Person
{
Name = "Alice",
Age = 20
};
オブジェクト初期化子は、
new した後にプロパティへ代入するコードの構文糖衣みたいな物。
オブジェクト名(p)が省略出来て便利。
var p = new Person();
p.Name = "Alice";
p.Age = 20;
さいごに
何となく使っていた言語機能を、あらためて整理してみました。
機能によっては、サンプルコードとして
スポット的に切り出してしまうと、
本来の使いどころが見えにくくなることもあります。
理解が深まったら再度整理し直したいと思います。

コメント