【C#】ラムダ式についてわかりやすく詳しく解説

ラムダ式は、簡潔で強力な機能を持ち、コードの可読性を向上させることができます。

本記事では、ラムダ式の基礎から応用までをサンプルコードを交えてわかりやすく解説します。

目次

ラムダ式とは何か

ラムダ式は、C# 3.0から導入された機能で、簡潔なコードで関数を定義することができます。

通常のメソッドや匿名メソッドよりも短く、読みやすく書けることが特徴です。

例えば、以下のような通常のメソッドがあったとします。

public int Add(int x, int y)
{
    return x + y;
}

これをラムダ式で表現すると以下のようになります。

(int x, int y) => x + y;

このように、引数部分を括弧で囲み、その後ろに=>を記述し、処理内容を記述します。

次の見出しでは、ラムダ式の基本的な使い方について説明します。

ラムダ式の基本構文

ラムダ式は、無名メソッドとも呼ばれます。

ラムダ式の基本構文は以下の通りです。

(parameter_list) => expression
  • parameter_list : ラムダ式に渡す引数のリストです。
  • => : ラムダ演算子と呼ばれます。
  • expression : ラムダ式が返す値を表します。

例えば、2つの整数を足し合わせるラムダ式は以下のように書くことができます。

(int x, int y) => x + y

この場合、(int x, int y)が引数リストであり、x + yが返り値です。

また、引数が1つだけの場合は以下のように省略することもできます。

x => x * x

この場合、(x)が引数リストであり、x * xが返り値です。

ラムダ式の使い方

ラムダ式は、C#で関数を簡潔に表現するための構文です。

ここでは、ラムダ式を使った簡単な計算、リストのフィルタリング、ソートについて説明します。

ラムダ式を使った簡単な計算

まずは、ラムダ式を使って簡単な計算をしてみましょう。

以下の例では、2つの引数を受け取り、足し算を行うラムダ式を定義しています。

Func<int, int, int> add = (x, y) => x + y;

このように定義したラムダ式は、以下のように呼び出すことができます。

int result = add(1, 2); // resultには3が代入される

関数を変数として扱えるため、ラムダ式の配列を用意して、順番に処理していくことも可能です。

ラムダ式を使ったリストのフィルタリング

次に、ラムダ式を使ってリストのフィルタリングを行ってみましょう。

以下の例では、整数型のリストから偶数だけを抽出するラムダ式を定義しています。

List<int> numbers = new List<int> { 1, 2, 3, 4, 5 };
var evenNumbers = numbers.Where(n => n % 2 == 0);

このように定義したラムダ式は、Whereメソッドと組み合わせて使用することで、条件に合致する要素だけが抽出されます。

上記の例ではevenNumbers変数には{2,4}が代入されます。

ラムダ式を使ったソート

最後に、ラムダ式を使ってソートしてみましょう。

以下の例では、文字列型のリストから文字列長で昇順に並べ替えるラムダ式を定義しています。

List<string> words = new List<string> { "apple", "banana", "cherry" };
var sortedWords = words.OrderBy(w => w.Length);

このように定義したラムダ式はOrderByメソッドと組み合わせて使用することで、指定した条件で要素が並べ替えられます。

上記の例ではsortedWords変数には{"apple", "cherry", "banana"}が代入されます。

以上がC#でラムダ式を使った簡単な計算やリストの基本的な操作方法です。

ラムダ式の注意点

ラムダ式を使用する際には、いくつかの注意点があります。

以下で詳しく解説します。

キャプチャ

ラムダ式内で外部変数を参照する場合、その変数をキャプチャする必要があります。

キャプチャとは、ラムダ式内で使用される外部変数の値を保持することです。

int x = 10;
Func<int> func = () => x; //直前の変数xを参照している
x = 20;
Console.WriteLine(func()); // 出力結果: 20

上記の例では、funcにはxへの参照が保持されています。

そのため、xの値が20に更新された後でも、func()からは最新の値である20が返されます。

ラムダ式内での処理や与える引数が同じでも、ラムダ式が呼び出されるタイミングで処理内容が変わる可能性があるので注意してください。

ラムダ式の型

C#では、「デリゲート」という概念を用いてメソッドや関数ポインターを扱います。

そして、「匿名メソッド」や「ラムダ式」もデリゲートとして扱われます。

しかし、「匿名メソッド」と「ラムダ式」は異なる型として扱われます。

具体的に言うと、「匿名メソッド」はdelegateという型で表現され、「ラムダ式」はExpression&lt;Func&lt;T, TResult&gt;&gt;という型で表現されます。

// 匿名メソッド
delegate (int a, int b) { return a + b; }

// ラムダ式
Expression<Func<int, int, int>> func = (a, b) => a + b;

この違いによって、「匿名メソッド」と「ラムダ式」では使える演算子や構文なども異なってきます。

ラムダ式の可読性

一般的に、「1行程度のシンプルな処理」以外では、複雑な処理を含んだ長いラムダ式は可読性が低下しやすくなります。

そのため、「分割代入」「ローカル関数」「拡張メソッド」「LINQクエリー構文」など他の手段も併用しながら可読性向上に努めましょう。

// 可読性低下例:長い処理を含んだ1行目
var result = list.Where(x => x.Age > 18 && x.Name.StartsWith("A")).OrderByDescending(x => x.Age).Select(x => new { Name = x.Name.ToUpper(), AgeGroup = GetAgeGroup(x.Age) });

// 可読性向上例:分割代入・ローカル関数・拡張メソッド・LINQクエリー構文等利用
var filteredList = list.Where(IsAdultAndStartsWithA);
var sortedList = filteredList.OrderByDescending(x => x.Age);
var mappedList = sortedList.Select(MapToAnonymousType);

private bool IsAdultAndStartsWithA(Person p)
{
    return p.Age > 18 && p.Name.StartsWith("A");
}

private object MapToAnonymousType(Person p)
{
    return new { Name = p.Name.ToUpper(), AgeGroup = GetAgeGroup(p.Age) };
}

var result2= mappedList.ToList();

2行目のラムダ式は非常に長く、可読性が極めて低いですが、その下ではメソッドを分割して可読性を上げています。

  • IsAdultAndStartsWithA: 分割代入・ローカル関数・拡張メソッド等利用した条件判断処理。
  • MapToAnonymousType: 分割代入・ローカル関数等利用したオブジェクトマッピング処理。
  • LINQクエリー構文: 読みやすさ向上。

目次