Linq-lambda-expressions

提供:Dev Guides
移動先:案内検索

LINQ-ラムダ式

「ラムダ式」という用語は、関数の定義に適用される数学表記法である「ラムダ」計算に由来しています。 LINQ方程式の実行可能部分としてのラムダ式は、実行時にロジックを変換して、データソースに簡単に渡すことができるようにします。 ただし、ラムダ式は、LINQでのみアプリケーションを見つけることに限定されていません。

これらの式は、次の構文で表されます-

(Input parameters) ⇒ Expression or statement block

これは、ラムダ式の例です-

y⇒y *y

上記の式はyという名前のパラメーターを指定し、yの値は2乗されます。 ただし、この形式でラムダ式を実行することはできません。 C#のラムダ式の例を以下に示します。

C#

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace lambdaexample {
   class Program {

      delegate int del(int i);
      static void Main(string[] args) {

         del myDelegate = y ⇒ y* y;
         int j = myDelegate(5);
         Console.WriteLine(j);
         Console.ReadLine();
      }
   }
}

VB

Module Module1
   Private Delegate Function del(ByVal i As Integer) As Integer

   Sub Main(ByVal args As String())

      Dim myDelegate As del = Function(y) y * y
      Dim j As Integer = myDelegate(5)
      Console.WriteLine(j)
      Console.ReadLine()

   End Sub

End Module

上記のC#またはVBのコードをコンパイルして実行すると、次の結果が生成されます-

25

式ラムダ

上記のラムダ式の構文の式は右側にあるため、これらは式ラムダとも呼ばれます。

非同期ラムダ

asyncキーワードを使用して非同期処理を組み込むことにより作成されるラムダ式は、非同期ラムダと呼ばれます。 以下は非同期ラムダの例です。

Func<Task<string>> getWordAsync = async()⇒ “hello”;

標準クエリ演算子のラムダ

クエリ演算子内のラムダ式は、オンデマンドで同じものによって評価され、シーケンス全体ではなく、入力シーケンスの各要素に対して継続的に機能します。 開発者は、Lambda式によって独自のロジックを標準クエリ演算子にフィードすることが許可されています。 以下の例では、開発者は「Where」演算子を使用して、ラムダ式を使用して特定のリストから奇数値を回収しています。

C#

//Get the average of the odd Fibonacci numbers in the series...

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace lambdaexample {
   class Program {
      static void Main(string[] args) {

         int[] fibNum = { 1, 1, 2, 3, 5, 8, 13, 21, 34 };
         double averageValue = fibNum.Where(num ⇒ num % 2 == 1).Average();
         Console.WriteLine(averageValue);
         Console.ReadLine();
      }
   }
}

VB

Module Module1

   Sub Main()

      Dim fibNum As Integer() = {1, 1, 2, 3, 5, 8, 13, 21, 34}
      Dim averageValue As Double = fibNum.Where(Function(num) num Mod 2 = 1).Average()

      Console.WriteLine(averageValue)
      Console.ReadLine()

   End Sub

End Module

上記のコードをコンパイルして実行すると、次の結果が生成されます-

7.33333333333333

Lambdaの型推論

C#では、型推論はさまざまな状況で便利に使用されますが、型を明示的に指定することもありません。 ただし、ラムダ式の場合、型の推論は、コンパイラが満たされる必要があるため、各型が指定されている場合にのみ機能します。 次の例を考えてみましょう。

delegate int Transformer (int i);

ここで、コンパイラは型推論を使用して、xが整数であるという事実を利用します。これは、Transformerのパラメーターの型を調べることで行われます。

Lambda式の変数スコープ

ラムダ式内で開始される変数が外部メソッドで表示されることを意図していないなど、ラムダ式で変数スコープを使用する際にいくつかのルールがあります。 また、キャプチャされた変数は、それを参照するデリゲートがガベージコレクションの動作に適格にならない限り、ガベージコレクションされないというルールがあります。 さらに、ラムダ式内のreturnステートメントを使用して、囲んでいるメソッドを返すことを禁止するルールがあります。

以下は、ラムダ式の変数スコープを示す例です。

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace lambdaexample {
   class Program {
      delegate bool D();
      delegate bool D2(int i);

      class Test {
         D del;
         D2 del2;

         public void TestMethod(int input) {
            int j = 0;
           //Initialize the delegates with lambda expressions.
           //Note access to 2 outer variables.
           //del will be invoked within this method.
            del = () ⇒ { j = 10; return j > input; };

           //del2 will be invoked after TestMethod goes out of scope.
            del2 = (x) ⇒ { return x == j; };

           //Demonstrate value of j:
           //The delegate has not been invoked yet.
            Console.WriteLine("j = {0}", j);       //Invoke the delegate.
            bool boolResult = del();

            Console.WriteLine("j = {0}. b = {1}", j, boolResult);
         }

         static void Main() {
            Test test = new Test();
            test.TestMethod(5);

           //Prove that del2 still has a copy of
           //local variable j from TestMethod.
            bool result = test.del2(10);

            Console.WriteLine(result);

            Console.ReadKey();
         }
      }
   }
}

上記のコードをコンパイルして実行すると、次の結果が生成されます-

j = 0
j = 10. b = True
True

式ツリー

ラムダ式は Expression Tree 構築で広範囲に使用されます。 式ツリーは、すべてのノード自体がメソッド呼び出しのような式であるか、x <yのような二項演算であるツリーに似たデータ構造のコードを提供します。 以下は、式ツリーを構築するためのラムダ式の使用例です。

ステートメントラムダ

2つまたは3つのステートメントで構成される*ステートメントラムダ*もありますが、式ツリーの構築には使用されません。 returnステートメントは、ステートメントlambdaで記述する必要があります。

ステートメントlambdaの構文

(params)⇒ {statements}

ステートメントラムダの例

using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Linq.Expressions;

namespace lambdaexample {
   class Program {
      static void Main(string[] args) {
         int[] source = new[] { 3, 8, 4, 6, 1, 7, 9, 2, 4, 8 };

         foreach (int i in source.Where(x ⇒
            {
               if (x <= 3)
                  return true;
               else if (x >= 7)
                  return true;
               return false;
            }
         ))
        Console.WriteLine(i);
        Console.ReadLine();
      }
   }
}

上記のコードをコンパイルして実行すると、次の結果が生成されます-

3
8
1
7
9
2
8

ラムダは、メソッドに基づくLINQクエリの引数として使用され、 isas のような演算子の左側に匿名メソッドのような場所を置くことは許可されません。 Lambda式は匿名メソッドによく似ていますが、これらはデリゲートとしてのみ使用されるように制限されていません。

ラムダ式を使用する際の注意点

  • ラムダ式は値を返すことができ、パラメーターを持つことができます。
  • パラメーターは、ラムダ式を使用してさまざまな方法で定義できます。
  • ラムダ式に単一のステートメントがある場合、中括弧の必要はありませんが、複数のステートメントがある場合、中括弧と戻り値は書くのに不可欠です。
  • ラムダ式では、クロージャーと呼ばれる機能により、ラムダ式ブロックの外側にある変数にアクセスできます。 問題を回避するために、クロージャーの使用は慎重に行う必要があります。
  • ラムダ式内で安全でないコードを実行することは不可能です。
  • ラムダ式は、演算子の左側で使用するためのものではありません。