PR

[C# 入門] 匿名関数(ラムダ式)の使い道 [使い方も解説]

ラムダ式を使うと名前のないメソッド(匿名関数)を書くことができます。
どういうときに使うのかというと、

  • イベントに登録するメソッドを書くときに使う
  • タスク(非同期処理)に登録するメソッドを書くときに使う
  • LINQのSelect、Whereメソッドのように引数にデリゲート型を持つメソッドに値を渡すのに使う
  • メソッド内のデリゲート型の変数に値(メソッド)を代入し、そのメソッド内で何度も呼び出す共通メソッドのように使う

という使い方ができます。

どれも、その処理からしか呼ばれないメソッドをわざわざ定義するのはめんどくさいしメソッドの呼び出し(指定)部分と定義部分が離れてコードに書いてあったら見にくいよね、という場合に使います。

デリゲート?ラムダ式?という人は[C#] デリゲートとラムダ式についてを見てください。

スポンサーリンク

ラムダ式の使い方

ラムダ式は引数のリスト処理ブロック=> でつなげて書きます。

(int a) => {
    var b = a * 10;
    return b;
}

処理ブロック { } の中が1つの式だけの場合、{ }return を省略して書くことができます。

(int a) => a * 10

引数リストは、型が推論できる(LINQのSelect、Whereメソッドの引数に指定する時など引数の型が分かっている)場合に、型指定を省略することができます。

// 引数が1つ場合は ( ) も省略できる
a => a * 10
// 引数が2つ以上の場合は ( ) は必須
(x, y) => x * y
スポンサーリンク

引数にデリゲート型を持つメソッドに値を渡す

LINQのSelectメソッドにラムダ式で匿名関数を渡してみます。

using System;
using System.Collections.Generic;
using System.Linq;
class Program
{
    public static void Main()
    {
        // ローカル変数a
        var a = 2;

        // リストの定義
        var ary1 = new List<int> { 1, 2, 3, 4, 5 };

        // Selectメソッドの引数にラムダ式でメソッドを渡す
        var ary2 = ary1.Select(i => i * a);

        // 結果を表示
        foreach (var i in ary2) Console.WriteLine(i);
    }
}

出力結果はこんな感じです。リストの各要素が2倍になりました。

2
4
6
8
10

ここで見てほしいのは、ary1.Select(i => i * a) の a の部分です。
aはサンプルコード9行目で宣言している変数a になります。
何が言いたいのかというと、匿名関数は外側にあるメソッドのローカル変数を使用することが出来るということです。外側にあるローカル変数のことを外部変数といいます。

同じクラスインスタンスのメンバー(フィールド、メソッド、プロパティなど)も外部変数として使うことができます。

また、匿名関数の中から変数aの値を変更することもできます。

using System;
using System.Collections.Generic;
using System.Linq;
class Program
{
    public static void Main()
    {
        // ローカル変数a
        var a = 2;

        // リストの定義
        var ary1 = new List<int> { 1, 2, 3, 4, 5 };

        // Selectメソッドの引数にラムダ式でメソッドを渡す
        var ary2 = ary1.Select(i => i * a++);

        // 結果を表示
        foreach (var i in ary2) Console.WriteLine(i);

        // ローカル変数aを表示
        Console.WriteLine($"変数a={a}");
    }
}
2
6
12
20
30
変数a=7
スポンサーリンク

メソッドの中でメソッドのように使う

デリゲート型の変数を使うとメソッドの中にメソッドを書くことができます。
デリゲートって何?という人はこちらを見てください。

[C#] デリゲートとラムダ式について
今回はデリゲート(delegate)とラムダ式についてです。イベントやLINQを使おうとすると出てくる用語ですね。 この2つがどういう関係かというと、「デリゲート型の変数や引数にラムダ式を使って値を代入する」ということをします。 デリゲート...

メソッドの中のデリゲート型の変数は以下のような性質があります。

  • 外側(定義しているメソッド内)の外部変数(ローカル変数など)を使用できる
  • 定義しているメソッド内からしか使えない(他と同じローカル変数なので)

外部変数を使用できるというのは、上で書いたラムダ式で引数に渡すときと同じです。

また、定義しているメソッド内でしか使えないので、「メソッド内で何度も使いたい処理があるけど他には公開したくない」という時にこのテクニックが役に立ちます。
メソッドAでしか使わない処理を新たにメソッドBとして定義して、他の人が誤って他の場所からメソッドBを呼び出してしまうということ防ぐことが出来ます。

using System;
class Program
{
    public static void Main()
    {
        // デリゲート型の変数にラムダ式で匿名関数を設定
        Action<object> act = (o) => Console.WriteLine(o);

        // デリゲート型の変数を使って匿名関数を呼び出す
        act("デリゲート型の変数にメソッドを入れて");
        act("なんども呼び出す");
        act("ことができます");
    }
}
スポンサーリンク

型推論varが使えるようになった(C#10から)

C#10からvarが使えるようになりました。

using System;
using System.Collections.Generic;

namespace LinqTest;
class Program
{
    static void Main() 
    {
        //Action になる
        var action1 = () => Console.WriteLine("引数なしのAction");

        //Action<int> になる
        var action2 = (int x) => Console.WriteLine("引数ありのAction");

        //引数の型を明示しないと推論できないのでエラーになる
        //var action3 = (x) => Console.WriteLine("引数の型を明示しないとだめ");

        //Func<string> になる
        var func1 = () => "引数なしのFunc";

        //Func<int, string> になる
        var func2 = (int x) => "引数ありのFunc";

        action1();
        action2(10);
        Console.WriteLine(func1());
        Console.WriteLine(func2(10));
    }
}
スポンサーリンク

ラムダ式にオプション引数が指定できるようになった(C#12から)

C#12からラムダ式の引数にオプション引数(デフォルト値)や可変長(params)を指定できるようになりました。

namespace ConsoleApp2
{
    internal class Program
    {
        static void Main(string[] args)
        {
            //オプション引数(デフォルト値)を指定できる
            var lambda1 = (int x = 1) => x + 1;

            Console.WriteLine($"lambda1()={lambda1()}");
            Console.WriteLine($"lambda1(10)={lambda1(10)}");

            //可変長(params)も指定できる
            var lambda2 = (params int[] x) => x.Sum();
            Console.WriteLine($"lambda2(1, 2, 3)={lambda2(1, 2, 3)}");
        }
    }
}
lambda1()=2
lambda1(10)=11
lambda2(1, 2, 3)=6

オプション引数についてはこちらの記事をどうぞ

[C# 入門] メソッドを呼び出す際に引数を省略可能にする
メソッドは渡されたパラメーター(引数)を元に処理を行い、戻り値を返します。メソッドを定義するときに引数を必須にするか、任意にするかを指定することができます。 メソッドを呼び出す際に任意の引数に値が指定されなかった場合は、既定値が設定されます...

可変長(params)についてはこちら、

[C# 入門] 可変長の引数を持つメソッドをつくる(params)
paramsキーワードをメソッドの引数に付けると引数の数を可変にすることができます。paramsキーワードを使えるのは配列だけです。 using System; class Program { public static void Main...

匿名関数(ラムダ式)の制限

匿名関数を書く際には以下の制限があります。

  • 引数の規定値を持つことが出来ない
  • イテレータにすることが出来ない
  • ジェネリックメソッドにすることが出来ない
  • 引数に ref 、out を付けることが出来ない

上のような制限なくメソッド内にメソッドを定義する方法にローカル関数を使った方法があります。
詳しくは、こちらの記事を見てください。

[C# 入門] ローカル関数(メソッド内にメソッドを定義する)
C#ではメソッドの中にメソッドを定義して使用することが出来ます。メソッド内で定義されたメソッドのことをローカル関数といいます。C#7.0からの機能です。 ローカル関数は定義されたメソッド内からのみアクセスすることができます。また、ローカル関...

C# 記事まとめページに戻る(他のサンプルコードもこちら)

C# プログラミング講座
C#についての記事まとめページです。開発環境VisualStudioのインストール方法や使い方、プログラミングの基礎知識についてや用語説明の記事一覧になっています。講座の記事にはすぐに実行できるようにサンプルコードを載せています。

コメント