C#ラムダ式とは?書き方・使い方・LINQでの活用を初心者向けにわかりやすく解説
はじめに
C#ラムダ式は、C#を学び始めた人がつまずきやすい文法のひとつです。特にLINQを使い始めると、x => x.Name や n => n > 10 のような書き方が頻繁に登場します。
最初は「この => は何?」「xはどこから来たの?」「普通のメソッドと何が違うの?」と感じるかもしれません。
しかし、C#ラムダ式の考え方はそれほど難しくありません。ラムダ式は、一言でいうと「その場で使う小さな処理を短く書くための記法」です。
この記事では、C#ラムダ式の基本構文、書き方、Func・Actionとの関係、LINQでの使い方、初心者がつまずきやすいポイントまで、サンプルコードを使ってわかりやすく解説します。
1. C#ラムダ式とは?初心者向けに一言で解説
C#ラムダ式とは、名前を付けずに処理を定義できる書き方です。
たとえば、数値を受け取って2倍にする処理は、ラムダ式を使うと次のように書けます。
C#x => x * 2
これは「xを受け取って、xの2倍を返す処理」と読めます。
1-1. ラムダ式は「名前のない処理」を短く書くための記法
通常、C#で処理をまとめる場合はメソッドを作ります。
C#int Double(int x)
{
return x * 2;
}
一方、ラムダ式ではこのような短い処理を、メソッド名なしで簡潔に書けます。
C#x => x * 2
このように、ラムダ式は「わざわざ名前付きメソッドを作るほどではない小さな処理」を書くときに便利です。
1-2. ラムダ式で使う「=>」ラムダ演算子の意味
ラムダ式で使われる => は、ラムダ演算子と呼ばれます。
C#x => x * 2
この式は、次のように読むと理解しやすくなります。
C#x を受け取って、x * 2 を返す
=> の左側には引数、右側には実行する処理を書きます。
C#引数 => 処理
つまり、=> は「左の値を使って、右の処理を行う」という意味だと考えるとわかりやすいです。
1-3. 通常のメソッド・匿名メソッドとの違い
通常のメソッドは、名前を付けて定義します。
C#int Add(int a, int b)
{
return a + b;
}
匿名メソッドは、名前なしで処理を書く古い書き方です。
C#delegate(int a, int b)
{
return a + b;
}
ラムダ式では、さらに短く書けます。
C#(a, b) => a + b
ラムダ式は匿名メソッドをより簡潔に書ける記法と考えると理解しやすいです。現在のC#では、LINQやイベント処理などでラムダ式がよく使われます。
1-4. ラムダ式がC#でよく使われる場面
C#ラムダ式は、主に次のような場面で使われます。
C#// LINQで条件に合うデータを取り出す
var adults = users.Where(user => user.Age >= 20);
// データを変換する
var names = users.Select(user => user.Name);
// イベント処理を書く
button.Click += (sender, e) =>
{
Console.WriteLine("クリックされました");
};
特にLINQではラムダ式が頻繁に登場します。そのため、C#で配列やListを扱うなら、ラムダ式の理解はとても重要です。
2. C#ラムダ式の基本構文と読み方
C#ラムダ式の基本は、次の形です。
C#引数 => 処理
左側に受け取る値、右側に実行する処理を書きます。
2-1. 基本形「引数 => 処理」の読み方
次のラムダ式を見てみましょう。
C#x => x + 1
これは次のように読みます。
C#xを受け取って、x + 1を返す
たとえば、xに10が入れば結果は11になります。
C#Func<int, int> addOne = x => x + 1;
Console.WriteLine(addOne(10)); // 11
Func<int, int> は「intを受け取ってintを返す処理」を表します。
2-2. 引数が1つの場合の書き方
引数が1つの場合は、引数をそのまま書けます。
C#x => x * 2
型を明示することもできます。
C#(int x) => x * 2
多くの場合、C#は代入先の型やLINQの対象から引数の型を推測できるため、型を省略できます。
C#Func<int, int> doubleValue = x => x * 2;
この場合、Func<int, int> から x は int だと判断されます。
2-3. 引数が複数ある場合の書き方
引数が複数ある場合は、丸かっこで囲みます。
C#(a, b) => a + b
使用例は次のとおりです。
C#Func<int, int, int> add = (a, b) => a + b;
Console.WriteLine(add(3, 5)); // 8
型を明示する場合は、次のように書きます。
C#Func<int, int, int> add = (int a, int b) => a + b;
2-4. 引数がない場合の書き方
引数がないラムダ式では、空の丸かっこを書きます。
C#() => Console.WriteLine("Hello")
例を見てみましょう。
C#Action sayHello = () => Console.WriteLine("Hello");
sayHello(); // Hello
Action は戻り値のない処理を表します。
2-5. 戻り値があるラムダ式の書き方
右側に式を書くラムダ式では、その式の結果がそのまま戻り値になります。
C#Func<int, int> square = x => x * x;
Console.WriteLine(square(4)); // 16
このようなラムダ式では、return を書きません。
C#// OK
x => x * x
// NG
x => return x * x;
return を使いたい場合は、波かっこ {} を使って複数行のラムダ式にします。
2-6. 複数行の処理を書くステートメントラムダ
複数行の処理を書きたい場合は、{} を使います。
C#Func<int, int> calculate = x =>
{
int result = x * 2;
return result + 10;
};
Console.WriteLine(calculate(5)); // 20
このように、波かっこを使うラムダ式をステートメントラムダと呼びます。
1行で書ける場合は式ラムダ、複数行の処理が必要な場合はステートメントラムダを使うとよいでしょう。
3. C#ラムダ式の具体的な書き方をサンプルコードで解説
ここからは、C#ラムダ式の具体的な書き方をサンプルコードで見ていきます。
3-1. 数値を受け取って計算するラムダ式
数値を2倍にするラムダ式です。
C#Func<int, int> doubleValue = x => x * 2;
Console.WriteLine(doubleValue(10)); // 20
2つの数値を足し算するラムダ式は次のように書けます。
C#Func<int, int, int> add = (a, b) => a + b;
Console.WriteLine(add(3, 7)); // 10
Func<int, int, int> の最後の int は戻り値の型です。つまり、「intを2つ受け取ってintを返す処理」を表しています。
3-2. 文字列を受け取って加工するラムダ式
文字列を受け取って、大文字に変換するラムダ式です。
C#Func<string, string> toUpper = text => text.ToUpper();
Console.WriteLine(toUpper("hello")); // HELLO
文字列の前後の空白を削除することもできます。
C#Func<string, string> trimText = text => text.Trim();
Console.WriteLine(trimText(" C# ")); // C#
文字列の長さを返すラムダ式は次のように書けます。
C#Func<string, int> getLength = text => text.Length;
Console.WriteLine(getLength("Lambda")); // 6
3-3. 条件判定に使うラムダ式
ラムダ式は条件判定にもよく使われます。
C#Func<int, bool> isEven = x => x % 2 == 0;
Console.WriteLine(isEven(4)); // True
Console.WriteLine(isEven(5)); // False
このラムダ式は「xを受け取って、xが偶数ならtrueを返す」という意味です。
条件判定には Predicate<T> を使うこともできます。
C#Predicate<int> isAdult = age => age >= 20;
Console.WriteLine(isAdult(25)); // True
3-4. Listや配列に対して使うラムダ式
ラムダ式はListや配列と組み合わせると便利です。
C#var numbers = new List<int> { 1, 2, 3, 4, 5 };
var evenNumbers = numbers.Where(x => x % 2 == 0);
foreach (var number in evenNumbers)
{
Console.WriteLine(number);
}
実行結果は次のようになります。
C#2
4
Where(x => x % 2 == 0) は、「xが偶数のものだけを取り出す」という意味です。
3-5. ラムダ式を変数に代入する書き方
ラムダ式は変数に代入できます。
C#Func<int, int> square = x => x * x;
int result = square(5);
Console.WriteLine(result); // 25
戻り値がない処理なら Action を使います。
C#Action<string> printMessage = message => Console.WriteLine(message);
printMessage("こんにちは");
このように、ラムダ式は単独では型を持つというより、Func や Action などの型に代入して使うことが多いです。
4. ラムダ式とデリゲート・Func・Actionの関係
C#ラムダ式を理解するうえで重要なのが、デリゲート、Func、Actionとの関係です。
ラムダ式は「処理の書き方」であり、その処理を受け取るための型が必要です。その代表がデリゲート、Func、Action、Predicateです。
4-1. ラムダ式を理解するために必要なデリゲートの基礎
デリゲートとは、メソッドや処理を変数のように扱うための型です。
C#delegate int Calculate(int x);
このデリゲートは、「intを受け取ってintを返す処理」を表します。
C#Calculate doubleValue = x => x * 2;
Console.WriteLine(doubleValue(10)); // 20
ここでは、ラムダ式 x => x * 2 を Calculate 型の変数に代入しています。
4-2. Funcで戻り値のあるラムダ式を扱う方法
Func は、戻り値がある処理を表すためによく使われます。
C#Func<int, int> doubleValue = x => x * 2;
これは「intを受け取ってintを返す処理」です。
引数が2つある場合は次のように書きます。
C#Func<int, int, int> add = (a, b) => a + b;
Func では、最後に書いた型が戻り値の型になります。
C#Func<引数の型, 戻り値の型>
Func<引数1の型, 引数2の型, 戻り値の型>
文字列を受け取って文字数を返す場合は、次のようになります。
C#Func<string, int> getLength = text => text.Length;
4-3. Actionで戻り値のないラムダ式を扱う方法
Action は、戻り値がない処理を表します。
C#Action<string> print = message => Console.WriteLine(message);
print("Hello");
引数がない場合は、次のように書きます。
C#Action sayHello = () => Console.WriteLine("Hello");
sayHello();
複数の引数を受け取ることもできます。
C#Action<string, int> showUser = (name, age) =>
{
Console.WriteLine($"{name}さんは{age}歳です");
};
showUser("田中", 25);
4-4. Predicateで条件判定を表す方法
Predicate<T> は、T型の値を受け取ってboolを返す処理を表します。
C#Predicate<int> isEven = x => x % 2 == 0;
Console.WriteLine(isEven(10)); // True
Listの Find メソッドなどで使えます。
C#var numbers = new List<int> { 1, 3, 5, 8, 10 };
int firstEven = numbers.Find(x => x % 2 == 0);
Console.WriteLine(firstEven); // 8
条件判定を表すラムダ式では、Func<T, bool> と Predicate<T> のどちらも使われることがあります。
4-5. 初心者が混乱しやすい「ラムダ式そのもの」と「代入先の型」の違い
初心者が混乱しやすいのは、ラムダ式だけを見ても型が決まらないことです。
C#x => x * 2
このラムダ式だけでは、xがintなのかdoubleなのか判断できません。
そのため、通常は代入先の型やメソッドの引数から型が決まります。
C#Func<int, int> doubleInt = x => x * 2;
Func<double, double> doubleDouble = x => x * 2;
同じように見えるラムダ式でも、代入先の型によって意味が変わることがあります。
つまり、ラムダ式は「処理の形」であり、Func や Action などが「その処理を受け取る型」だと考えると理解しやすくなります。
5. LINQでのラムダ式の使い方
C#ラムダ式が最もよく使われる場面のひとつがLINQです。
LINQを使うと、Listや配列などのデータに対して、検索、絞り込み、変換、並び替え、集計などを簡潔に書けます。
5-1. LINQでラムダ式がよく使われる理由
LINQでは、「どの条件で絞り込むか」「どの値を取り出すか」「何を基準に並び替えるか」といった処理を指定する必要があります。
その指定にラムダ式がよく使われます。
C#var adults = users.Where(user => user.Age >= 20);
このコードでは、user => user.Age >= 20 が「20歳以上のユーザーを選ぶ条件」を表しています。
ラムダ式を使うことで、条件や変換処理をその場で簡潔に書けます。
5-2. Whereで条件に合う要素を絞り込む
Where は、条件に合う要素だけを取り出すメソッドです。
C#var numbers = new List<int> { 1, 2, 3, 4, 5, 6 };
var evenNumbers = numbers.Where(n => n % 2 == 0);
foreach (var number in evenNumbers)
{
Console.WriteLine(number);
}
実行結果は次のとおりです。
C#2
4
6
n => n % 2 == 0 は、「nが偶数ならtrue」という条件です。
5-3. Selectでデータを変換する
Select は、各要素を別の形に変換するメソッドです。
C#var names = new List<string> { "Tanaka", "Suzuki", "Sato" };
var nameLengths = names.Select(name => name.Length);
foreach (var length in nameLengths)
{
Console.WriteLine(length);
}
文字列を別の文字列に変換することもできます。
C#var messages = names.Select(name => $"{name}さん、こんにちは");
foreach (var message in messages)
{
Console.WriteLine(message);
}
Select は、データを一覧表示用の形に変えたいときによく使います。
5-4. OrderByで並び替える
OrderBy は、指定した値を基準に昇順で並び替えます。
C#var numbers = new List<int> { 5, 2, 8, 1, 3 };
var sortedNumbers = numbers.OrderBy(n => n);
foreach (var number in sortedNumbers)
{
Console.WriteLine(number);
}
オブジェクトのプロパティを基準に並び替えることもできます。
C#var users = new List<User>
{
new User { Name = "田中", Age = 30 },
new User { Name = "佐藤", Age = 20 },
new User { Name = "鈴木", Age = 25 }
};
var sortedUsers = users.OrderBy(user => user.Age);
降順に並び替える場合は OrderByDescending を使います。
C#var sortedUsers = users.OrderByDescending(user => user.Age);
5-5. Any・Allで条件を満たすか判定する
Any は、条件を満たす要素が1つでもあるかを判定します。
C#var numbers = new List<int> { 1, 3, 5, 8 };
bool hasEven = numbers.Any(n => n % 2 == 0);
Console.WriteLine(hasEven); // True
All は、すべての要素が条件を満たすかを判定します。
C#var scores = new List<int> { 80, 90, 75 };
bool allPassed = scores.All(score => score >= 60);
Console.WriteLine(allPassed); // True
Any と All は、存在チェックや入力チェックでよく使います。
5-6. FirstOrDefaultで最初の要素を取得する
FirstOrDefault は、条件に合う最初の要素を取得します。見つからない場合は既定値を返します。
C#var numbers = new List<int> { 1, 3, 5, 8, 10 };
int firstEven = numbers.FirstOrDefault(n => n % 2 == 0);
Console.WriteLine(firstEven); // 8
オブジェクトの検索にも使えます。
C#var user = users.FirstOrDefault(u => u.Name == "田中");
ただし、見つからなかった場合は null になることがあるため、参照型ではnullチェックを忘れないようにしましょう。
C#if (user != null)
{
Console.WriteLine(user.Age);
}
5-7. Count・Sum・Averageで集計する
Count は条件に合う要素数を数えます。
C#var numbers = new List<int> { 1, 2, 3, 4, 5 };
int evenCount = numbers.Count(n => n % 2 == 0);
Console.WriteLine(evenCount); // 2
Sum は合計を求めます。
C#int total = numbers.Sum(n => n);
Console.WriteLine(total); // 15
オブジェクトのプロパティを集計することもできます。
C#var totalPrice = products.Sum(p => p.Price);
Average は平均を求めます。
C#double average = numbers.Average(n => n);
Console.WriteLine(average); // 3
5-8. LINQのメソッド構文とクエリ構文の違い
LINQには、メソッド構文とクエリ構文があります。
メソッド構文では、ラムダ式をよく使います。
C#var adults = users
.Where(user => user.Age >= 20)
.Select(user => user.Name);
クエリ構文では、SQLのような書き方をします。
C#var adults =
from user in users
where user.Age >= 20
select user.Name;
どちらも同じような処理を書けますが、C#ではメソッド構文とラムダ式の組み合わせがよく使われます。まずは Where、Select、OrderBy をラムダ式で書けるようになるとよいでしょう。
6. ラムダ式を使うメリット・注意点
C#ラムダ式は便利ですが、使い方を間違えると読みにくいコードになることもあります。メリットと注意点を確認しておきましょう。
6-1. コードを短く読みやすく書ける
ラムダ式を使うと、短い処理を簡潔に書けます。
C#var adults = users.Where(user => user.Age >= 20);
これを通常のメソッドで書くと、別途メソッドを定義する必要があります。
C#bool IsAdult(User user)
{
return user.Age >= 20;
}
var adults = users.Where(IsAdult);
条件が短く、その場でしか使わないならラムダ式のほうが読みやすくなります。
6-2. その場限りの処理を簡潔に定義できる
一度しか使わない処理のためにメソッド名を考えるのは、かえって手間になることがあります。
C#var expensiveProducts = products.Where(p => p.Price >= 10000);
このように、処理の内容が単純であればラムダ式でその場に書いたほうが自然です。
6-3. LINQやイベント処理と相性がよい
ラムダ式はLINQと非常に相性がよいです。
C#var names = users
.Where(u => u.Age >= 20)
.OrderBy(u => u.Name)
.Select(u => u.Name);
また、イベント処理でもよく使われます。
C#button.Click += (sender, e) =>
{
Console.WriteLine("ボタンがクリックされました");
};
短いイベント処理であれば、ラムダ式を使うことでコードをコンパクトにできます。
6-4. 書きすぎると逆に読みにくくなる
ラムダ式は便利ですが、複雑な処理を詰め込みすぎると読みにくくなります。
C#var result = users.Where(u => u.Age >= 20 && u.Name.StartsWith("A") && u.Orders.Any(o => o.TotalPrice > 10000));
この程度ならまだ読めますが、条件がさらに増えると理解しづらくなります。
読みづらいと感じたら、条件をメソッドに分けることを検討しましょう。
C#bool IsTargetUser(User user)
{
return user.Age >= 20
&& user.Name.StartsWith("A")
&& user.Orders.Any(order => order.TotalPrice > 10000);
}
var result = users.Where(IsTargetUser);
6-5. 複雑な処理は通常のメソッドに分けるべき理由
複雑な処理をラムダ式に詰め込むと、次のような問題が起きやすくなります。
処理の意図がわかりにくい
デバッグしづらい
同じ処理を再利用しにくい
テストしにくい
ラムダ式は「短くて単純な処理」に向いています。複雑な処理や何度も使う処理は、通常のメソッドとして名前を付けると読みやすくなります。
7. 初心者がつまずきやすいC#ラムダ式のポイント
C#ラムダ式では、初心者が混乱しやすいポイントがいくつかあります。ここでは特に重要な点を整理します。
7-1. 「x => x + 1」のxは何を表しているのか
x => x + 1 の x は、ラムダ式に渡される引数です。
C#Func<int, int> addOne = x => x + 1;
この場合、xはint型の値です。
C#Console.WriteLine(addOne(10)); // 11
LINQでは、xはコレクションの各要素を表します。
C#var numbers = new List<int> { 1, 2, 3 };
var result = numbers.Select(x => x + 1);
この場合、xには1、2、3が順番に入ります。
つまり、ラムダ式の引数名は自由に決められます。xである必要はありません。
C#var result = numbers.Select(number => number + 1);
読みやすさを重視するなら、x よりも number や user のように意味のある名前を使うとよいでしょう。
7-2. 引数の型を省略できる理由
ラムダ式では、引数の型を省略することがよくあります。
C#Func<int, int> doubleValue = x => x * 2;
これは、代入先の Func<int, int> から、xがint型だと判断できるためです。
LINQでも同じです。
C#var numbers = new List<int> { 1, 2, 3 };
var result = numbers.Where(n => n > 1);
numbers は List<int> なので、nはint型だと推測されます。
型を明示したい場合は、次のようにも書けます。
C#var result = numbers.Where((int n) => n > 1);
ただし、通常は型を省略したほうが読みやすいことが多いです。
7-3. returnを書ける場合・書けない場合
式ラムダでは return を書きません。
C#Func<int, int> square = x => x * x;
次の書き方はエラーになります。
C#Func<int, int> square = x => return x * x;
return を書く場合は、波かっこ {} を使います。
C#Func<int, int> square = x =>
{
return x * x;
};
1行で結果を返すだけなら、return なしの式ラムダを使うのが一般的です。
7-4. {}を使う場合と使わない場合の違い
{} を使わないラムダ式は、右側に式を1つだけ書きます。
C#x => x * 2
この場合、式の結果が自動的に戻り値になります。
一方、{} を使う場合は、通常のメソッド本体のように複数行の処理を書けます。
C#x =>
{
int result = x * 2;
return result;
}
戻り値がある場合、{} の中では return が必要です。
C#Func<int, int> func = x =>
{
return x * 2;
};
戻り値がない場合は return は不要です。
C#Action<string> print = message =>
{
Console.WriteLine(message);
};
7-5. ラムダ式内で外側の変数を使うときの注意点
ラムダ式の中では、外側で定義された変数を使うことができます。
C#int threshold = 20;
var adults = users.Where(user => user.Age >= threshold);
このように、ラムダ式が外側の変数を参照することをクロージャと呼びます。
便利な機能ですが、外側の変数が後から変更されると、ラムダ式の結果も変わる場合があります。
C#int value = 10;
Func<int> getValue = () => value;
value = 20;
Console.WriteLine(getValue()); // 20
ラムダ式は変数の値そのものではなく、変数を参照している点に注意しましょう。
7-6. Nullや空コレクションを扱うときの注意点
LINQとラムダ式を使うときは、nullに注意が必要です。
C#List<string>? names = null;
// エラーになる
var result = names.Where(name => name.Length > 3);
nullの可能性がある場合は、先にチェックしましょう。
C#if (names != null)
{
var result = names.Where(name => name.Length > 3);
}
また、要素がnullの可能性がある場合も注意が必要です。
C#var names = new List<string?> { "Tanaka", null, "Sato" };
var result = names.Where(name => name != null && name.Length > 3);
空のコレクションに対して Where や Select を使うこと自体は問題ありません。ただし、First は要素がないと例外になるため、必要に応じて FirstOrDefault を使いましょう。
C#var first = names.FirstOrDefault();
8. C#ラムダ式の実践例
ここでは、C#ラムダ式を実際の開発で使う例を紹介します。
8-1. ユーザー一覧から条件に合うユーザーを検索する
ユーザー一覧から20歳以上のユーザーを検索する例です。
C#public class User
{
public string Name { get; set; } = "";
public int Age { get; set; }
}
var users = new List<User>
{
new User { Name = "田中", Age = 30 },
new User { Name = "佐藤", Age = 18 },
new User { Name = "鈴木", Age = 25 }
};
var adults = users.Where(user => user.Age >= 20);
foreach (var user in adults)
{
Console.WriteLine(user.Name);
}
user => user.Age >= 20 が検索条件です。
特定の名前のユーザーを1人だけ取得する場合は、FirstOrDefault を使えます。
C#var targetUser = users.FirstOrDefault(user => user.Name == "田中");
if (targetUser != null)
{
Console.WriteLine(targetUser.Age);
}
8-2. 商品一覧を価格順に並び替える
商品一覧を価格の安い順に並び替える例です。
C#public class Product
{
public string Name { get; set; } = "";
public int Price { get; set; }
}
var products = new List<Product>
{
new Product { Name = "キーボード", Price = 5000 },
new Product { Name = "マウス", Price = 2000 },
new Product { Name = "モニター", Price = 30000 }
};
var sortedProducts = products.OrderBy(product => product.Price);
foreach (var product in sortedProducts)
{
Console.WriteLine($"{product.Name}: {product.Price}円");
}
高い順に並び替える場合は、OrderByDescending を使います。
C#var expensiveFirst = products.OrderByDescending(product => product.Price);
8-3. データを別の形に変換して一覧表示する
Select を使うと、データを表示用の文字列に変換できます。
C#var productLabels = products.Select(product => $"{product.Name}({product.Price}円)");
foreach (var label in productLabels)
{
Console.WriteLine(label);
}
オブジェクトを別の形のオブジェクトに変換することもできます。
C#var summaries = products.Select(product => new
{
DisplayName = product.Name,
TaxIncludedPrice = product.Price * 1.1
});
このように、ラムダ式はデータの変換処理でもよく使われます。
8-4. ボタンクリックなどのイベント処理で使う
ラムダ式はイベント処理でも使えます。
C#button.Click += (sender, e) =>
{
Console.WriteLine("ボタンがクリックされました");
};
短い処理なら1行で書くこともできます。
C#button.Click += (sender, e) => Console.WriteLine("クリック");
ただし、イベント処理が複雑になる場合は、通常のメソッドに分けたほうが読みやすくなります。
C#button.Click += Button_Click;
void Button_Click(object? sender, EventArgs e)
{
Console.WriteLine("ボタンがクリックされました");
}
8-5. 非同期処理やコールバックで使う
ラムダ式は非同期処理でも使えます。
C#Func<Task> loadDataAsync = async () =>
{
await Task.Delay(1000);
Console.WriteLine("データを読み込みました");
};
await loadDataAsync();
イベント処理で非同期ラムダを使うこともあります。
C#button.Click += async (sender, e) =>
{
await Task.Delay(1000);
Console.WriteLine("非同期処理が完了しました");
};
非同期ラムダでは、async と await を組み合わせて使います。ただし、例外処理が見えにくくなることがあるため、複雑な非同期処理はメソッドに分けると安全です。
9. C#ラムダ式を理解するための練習問題
C#ラムダ式は、実際に手を動かして書くと理解しやすくなります。ここでは練習問題を紹介します。
9-1. ラムダ式の読み方を確認する問題
次のラムダ式が何をしているか考えてみましょう。
C#x => x * 3
答えは、「xを受け取って、xを3倍した値を返す」です。
次のラムダ式はどうでしょうか。
C#name => name.Length
これは、「nameを受け取って、文字数を返す」です。
次のラムダ式は条件判定です。
C#age => age >= 20
これは、「ageが20以上ならtrueを返す」です。
9-2. 通常のメソッドをラムダ式に書き換える問題
次のメソッドをラムダ式に書き換えてみましょう。
C#int Double(int x)
{
return x * 2;
}
ラムダ式では次のように書けます。
C#Func<int, int> doubleValue = x => x * 2;
次のメソッドも見てみましょう。
C#bool IsAdult(int age)
{
return age >= 20;
}
ラムダ式では次のように書けます。
C#Func<int, bool> isAdult = age => age >= 20;
または、条件判定用に Predicate<int> を使うこともできます。
C#Predicate<int> isAdult = age => age >= 20;
9-3. LINQとラムダ式を組み合わせる問題
次のListから偶数だけを取り出してみましょう。
C#var numbers = new List<int> { 1, 2, 3, 4, 5, 6 };
答えは次のようになります。
C#var evenNumbers = numbers.Where(n => n % 2 == 0);
次に、各数値を2倍に変換してみましょう。
C#var doubled = numbers.Select(n => n * 2);
最後に、3より大きい数だけを取り出して、昇順に並べてみます。
C#var result = numbers
.Where(n => n > 3)
.OrderBy(n => n);
このように、LINQではラムダ式を組み合わせてデータ処理を書けます。
9-4. よくあるエラーを修正する問題
次のコードはエラーになります。
C#Func<int, int> square = x => return x * x;
式ラムダでは return を書けません。修正すると次のようになります。
C#Func<int, int> square = x => x * x;
または、波かっこを使います。
C#Func<int, int> square = x =>
{
return x * x;
};
次のコードも注意が必要です。
C#var user = users.First(u => u.Name == "山田");
条件に合うユーザーがいない場合、First は例外になります。見つからない可能性がある場合は FirstOrDefault を使いましょう。
C#var user = users.FirstOrDefault(u => u.Name == "山田");
if (user != null)
{
Console.WriteLine(user.Age);
}
10. C#ラムダ式に関するよくある質問
最後に、C#ラムダ式に関するよくある質問をまとめます。
10-1. ラムダ式と匿名関数の違いは?
ラムダ式は匿名関数の一種です。
匿名関数とは、名前を持たない関数のことです。C#では、匿名メソッドとラムダ式が匿名関数に含まれます。
匿名メソッドは次のように書きます。
C#delegate(int x)
{
return x * 2;
}
ラムダ式では、より短く書けます。
C#x => x * 2
現在のC#では、匿名メソッドよりラムダ式のほうがよく使われます。
10-2. ラムダ式とLINQは同じもの?
ラムダ式とLINQは同じものではありません。
ラムダ式は、名前のない処理を簡潔に書くための記法です。
LINQは、コレクションやデータに対して検索、絞り込み、変換、集計などを行うための仕組みです。
ただし、LINQのメソッド構文ではラムダ式をよく使います。
C#var adults = users.Where(user => user.Age >= 20);
このため、C#ラムダ式とLINQはセットで学ぶと理解しやすくなります。
10-3. ラムダ式は必ず使わないといけない?
ラムダ式は必ず使わなければならないものではありません。
通常のメソッドでも同じ処理を書けます。
C#bool IsAdult(User user)
{
return user.Age >= 20;
}
var adults = users.Where(IsAdult);
ただし、短い処理やその場限りの処理では、ラムダ式を使ったほうが簡潔です。
C#var adults = users.Where(user => user.Age >= 20);
重要なのは、ラムダ式を使うこと自体ではなく、読みやすいコードを書くことです。
10-4. ラムダ式の型は何になる?
ラムダ式は、代入先や渡される先によって型が決まります。
たとえば、次のラムダ式は Func<int, int> に代入されています。
C#Func<int, int> doubleValue = x => x * 2;
戻り値がない場合は Action に代入できます。
C#Action<string> print = message => Console.WriteLine(message);
条件判定の場合は Predicate<T> や Func<T, bool> が使われます。
C#Predicate<int> isEven = x => x % 2 == 0;
Func<int, bool> isOdd = x => x % 2 != 0;
つまり、ラムダ式そのものだけで型を判断するのではなく、どの型に代入されるか、どのメソッドに渡されるかによって型が決まります。
10-5. 初心者はどこまで覚えればよい?
初心者は、まず次の5つを覚えれば十分です。
1つ目は、ラムダ式の基本形です。
C#引数 => 処理
2つ目は、x => x * 2 のように「左が引数、右が処理」だと読めることです。
3つ目は、LINQの Where、Select、OrderBy でラムダ式がよく使われることです。
C#numbers.Where(n => n > 10)
names.Select(name => name.Length)
users.OrderBy(user => user.Age)
4つ目は、戻り値がある処理には Func、戻り値がない処理には Action を使うことです。
5つ目は、複雑な処理を無理にラムダ式で書かず、必要に応じて通常のメソッドに分けることです。
最初からすべてを完璧に理解する必要はありません。まずはLINQの中でラムダ式を読めるようになることを目標にしましょう。
まとめ
C#ラムダ式は、名前のない処理を短く書くための記法です。
基本形は次のとおりです。
C#引数 => 処理
たとえば、数値を2倍にする処理は次のように書けます。
C#x => x * 2
ラムダ式は、Func、Action、Predicate などの型に代入して使えます。
C#Func<int, int> doubleValue = x => x * 2;
Action<string> print = message => Console.WriteLine(message);
Predicate<int> isEven = x => x % 2 == 0;
また、C#ラムダ式はLINQと非常に相性がよく、Where、Select、OrderBy、Any、FirstOrDefault などで頻繁に使われます。
C#var adults = users.Where(user => user.Age >= 20);
var names = users.Select(user => user.Name);
var sortedUsers = users.OrderBy(user => user.Age);
ラムダ式を使うと、短い処理をその場で簡潔に書けます。ただし、複雑な処理を詰め込みすぎると読みにくくなるため、必要に応じて通常のメソッドに分けることも大切です。
初心者のうちは、まず「x => x + 1 は、xを受け取ってx + 1を返す処理」と読めるようになれば十分です。そこからLINQのサンプルを少しずつ書いていくことで、C#ラムダ式の使い方が自然に身についていきます。

