C# 今更ですが、ラムダ式

# 最初に

一体何番煎じの記事なんだ…

でも、C#の初心者が順番に文法を学んでいって、最初に詰まるところはラムダ式じゃないかな、と思います。理由ははっきりしていて、ラムダ式だけ考え方、つまり頭の使い方が違うんですよね。この記事が理解の足しになればな、と思います。

# またいつものループ処理か…

`List<T>`の各要素に対して XX 処理をする、というのは、C#をやっていると頻繁に出くわすのではないでしょうか？　例えば `List<string>`の各要素の文字列に対して、`".txt"`を付ける、みたいな処理です。まぁ、`foreach`でいいですよね。

```csharp
var list = new List<string>(); // このListの各要素に".txt"をつける

var result = new List<string>();
foreach (var s in list)
{
    result.Add(s + ".txt");
}
```

何が悪いかって、面倒なんですよね、毎回毎回`foreach`書くのが。初心者の人はまだ100回くらいかもしれませんが、私はもう10000回くらい書いてるよ。いやそんなことよりもっと大きな問題がある。`List<string>`の各要素に対しての処理なら、`List<string>`の処理として、つまりメソッドを用意して欲しい、ということだ。

つまり、こう書きたいのです。

```csharp
var list = new List<string>(); // このListの各要素に".txt"をつける

var result = list.Select(文字列に".txt"を付けたす処理);
```

ここで問題になるのは、<font color='#AA0000'>文字列に".txt"を付けたす処理</font>の部分で、Selectメソッドの引数に何の**値**を渡せばいいか、ということです。渡せるモノは**値**なんですよ、メソッドの引数ですから。でも今渡したいのは、文字列に".txt"を付けたす**処理**で、プログラムで ～処理 、と見たら、ほぼそれは機械的にメソッド/関数と脳内置換していいです。つまり今`Select`メソッドに渡したいモノは**値**ではなく**メソッド**なのです。

# じゃあ、メソッドをメソッドに渡しちゃおう

そこでMicrosoftは考えたのですよ、別にメソッドを渡せてもいいんじゃないかな、と。メソッドに値を渡す場合、変数定義（宣言）して、それを渡しますよね、こんな風に。

```csharp
var list = new List<string>();
var s = "hoge"; // ← Addメソッドに渡す変数を定義（宣言）

list.Add(s);
```

だからメソッドを渡す場合も、メソッドを定義しておく必要があります。

```csharp
public static void Main(string[] args)
{
    var list = new List<string>(); // このListの各要素に".txt"をつける

    var result = list.Select(Append);
}

// ↓ Selectメソッドに渡すメソッドを定義
private static string Append(string s)
{
    return s + ".txt";
}
```

これはこれでいいのですが、こんな中身がちっちゃいメソッドをわざわざ作りたくないんですよね、メソッド名を考えるのが嫌になってくるから。でもメソッドに値を渡す場合は、変数なんて定義（宣言）しなくても、値を直接（リテラル）書けますよね。

```csharp
var list = new List<string>();

list.Add("hoge"); // ← 直接リテラルを書く
```

メソッドもリテラルが書けてもいいともいませんか？　こういう風に。

```csharp
public static void Main(string[] args)
{
    var list = new List<string>(); // このListの各要素に".txt"をつける

    var result = list.Select((string s) => { return s + ".txt"; }); // ← 直接リテラルを書く
}
```

`list.Select(Append)`の`Append`メソッドの中身を強引に展開しました。それによって、Appendというメソッド名も必要なくなりました。はい、**これがラムダ式**です。簡単ですね。

# なんか、いつもよく見かけるラムダ式と少しちがうような

`(string s) => { return s + ".txt"; }`の部分がラムダ式なのですが、なにか微妙に記述が違います。いつも見かけるのは、このラムダ式の省略記法で、純粋にC#の文法・記述のだけの話です。

C#のラムダ式の記法は、次の場合省略できます。

- 引数の型が自明（型推論が出来る）の場合、省略できる。

```csharp
(string s) => { return s + ".txt"; }
```
↓

```csharp
(s) => { return s + ".txt"; }
```

- メソッド本体が１文しかない（正確には式しかない）場合は、`{ }`と`return`を省略できる。

```csharp
(s) => { return s + ".txt"; }
```
↓

```csharp
(s) => s + ".txt"
```

- 引数が１つの場合は`( )`を省略できる（引数０はダメ）。

```csharp
(s) => s + ".txt"
```
↓

```csharp
s => s + ".txt"
```

これでよく見かけるラムダ式になりました。最初、慣れない間は`()`や`{}`を補ってあげると良いです。慣れれば自然と分かるようになります。

```csharp
var result = list.Select(s => s + ".txt");
```
↓

```csharp
var result = list.Select((string s) => { return s + ".txt"});
```

# 便利なので、自分でもメソッドを受け取るメソッドを作りたい

今までは使う側だったのですが、こんどは作る側（提供する側）です。ぱっといい例が思いつかなかったのでが、ファイルを読んで、各行をなんらかの変換して`List`を返すメソッドを作るとしましょう。なんらかの変換は、呼び出し側にメソッドを指定してもらって、trimするとか".txt"付け足すとかできるようにしましょう。ラムダ式の出番です。メソッドを書いてみましょう。こんな感じでしょうか。

```csharp
public IEnumerable<string> Read(string path, 文字列を引数にとって文字列を返すメソッド fx)
{
    var result = new List<string>();

    using (var reader = new StreamReader(path))
    {
        while (reader.Peek() >= 0)
        {
            var line = reader.ReadLine();
            result.Add(fx(line));
        }
    }

    return result;
}
```

１つ困ったことが発生しました。C#の文法だと、メソッドの定義は`型＋（仮）変数名`なのですが、**メソッドを受け取る引数**は、いったいどうやって書けばいいのでしょうか？　<font color='#AA0000'>文字列を引数にとって文字列を返すメソッド</font>の部分です。

当然、**メソッドを表す型**です。C#にメソッドを受け取る書き方ができる文法が用意されていればよかったのですが、そんなのはありません、というかMicrosoftはそんなの不要、と判断したのでしょう。だからメソッドを表す型があるのです。

それが、`Func`と`Action`です。この２つは本質的に同じもので、使い分けは、
戻り値がある（voidじゃない） → `Func`
戻り値がない（void） → `Action`
だけです。これはC#のジェネリックス型引数に`void`が指定できないから、２種類あるだけです。voidが指定できたら２種類いらなかった。

今回の例は、戻り値があるので`Func`を使います。引数：文字列、戻り値：文字列、なので、型は`Func<string, string>`になります。

```csharp
public IEnumerable<string> Read(string path, Func<string, string> fx)
{
...
```

これで、無事呼び出し側から、ラムダ式を受け取れます。

```csharp
Read("hoge.txt", s => s + ".txt");
```

# まとめ

ラムダ式の説明としては、まだ遅延評価と副作用の話がありますが、とりあえずこれだけ理解しておけば当面困らないと思います。ラムダ式の理解がつまづくのは、今まではメソッドに値を渡すという、値ベースの考え方なのですが、ラムダ式で急にメソッド（処理）を渡すという、関数型指向の考え方が出てくるからです。

# 最後に１つだけ言っておきたいことがある

`delegate`なんてなかった、いいね？