web-dev-qa-db-ja.com

C#ラムダ式:なぜそららを使うべきなのか

私はすぐに Microsoft Lambda Expression のドキュメントを読みました。

この種の例は私がよりよく理解するのを助けました、しかし:

delegate int del(int i);
del myDelegate = x => x * x;
int j = myDelegate(5); //j = 25

それでも、なぜそれがそんなに革新的なのか理解できません。 「メソッド変数」が終了したときに死ぬのは単なるメソッドですね。本当の方法ではなくこれを使うべきなのはなぜですか?

296

ラムダ式 は、匿名デリゲートにとってより単純な構文であり、匿名デリゲートを使用できるところならどこでも使用できます。しかし、その逆は真実ではありません。ラムダ式は式ツリーに変換でき、LINQ to SQLのような多くの魔法を可能にします。

以下は、匿名デリゲートを使用してラムダ式を使用して、 オブジェクトへのLINQ式 の式の例です。

// anonymous delegate
var evens = Enumerable
                .Range(1, 100)
                .Where(delegate(int x) { return (x % 2) == 0; })
                .ToList();

// lambda expression
var evens = Enumerable
                .Range(1, 100)
                .Where(x => (x % 2) == 0)
                .ToList();

ラムダ式と匿名デリゲートは別の関数を書くよりも利点があります。それらは クロージャー を実装して、 渡すことを可能にします。関数にパラメータ を追加したり、使い捨てオブジェクトを作成したりすることなく、関数にローカル状態を設定します。

式ツリー はC#3.0の非常に強力な新機能で、メソッドへの参照を取得する代わりにAPIが式の構造を調べることを可能にします。それは実行することができます。 APIは単にデリゲートパラメータをExpression<T>パラメータにするだけでよく、コンパイラは無名デリゲートの代わりにラムダから式ツリーを生成します。

void Example(Predicate<int> aDelegate);

のように呼ばれる:

Example(x => x > 5);

になります:

void Example(Expression<Predicate<int>> expressionTree);

後者は式x > 5を記述する 抽象構文木 の表現を渡されます。 LINQ to SQLはこの振る舞いを利用して、C#式をサーバー側でのフィルタリングや順序付けなどに必要なSQL式に変換できるようにします。

276
Neil Williams

無名関数と式は、完全なメソッドを作成するのに必要な余分な作業から恩恵を受けない一回限りのメソッドに役立ちます。

この例を考えてください。

 string person = people.Find(person => person.Contains("Joe"));

versus

 public string FindPerson(string nameContains, List<string> persons)
 {
     foreach (string person in persons)
         if (person.Contains(nameContains))
             return person;
     return null;
 }

これらは機能的に同等です。

135
Joseph Daigle

別のコントロールを使用して、あるコントロールのイベント用のハンドラを宣言したい場合に、それらが役に立つことがわかりました。通常それを行うには、コントロールの参照をクラスのフィールドに格納して、それらが作成されたものとは異なるメソッドで使用できるようにする必要があります。

private ComboBox combo;
private Label label;

public CreateControls()
{
    combo = new ComboBox();
    label = new Label();
    //some initializing code
    combo.SelectedIndexChanged += new EventHandler(combo_SelectedIndexChanged);
}

void combo_SelectedIndexChanged(object sender, EventArgs e)
{
    label.Text = combo.SelectedValue;
}

ラムダ式のおかげで、このように使うことができます。

public CreateControls()
{
    ComboBox combo = new ComboBox();
    Label label = new Label();
    //some initializing code
    combo.SelectedIndexChanged += (s, e) => {label.Text = combo.SelectedValue;};
}

はるかに簡単です。

84
agnieszka

LambdaはC#2.0の匿名デリゲート構文を整理しました...例えば

Strings.Find(s => s == "hello");

このようにC#2.0で行われました:

Strings.Find(delegate(String s) { return s == "hello"; });

機能的には、それらはまったく同じことをします。それはただもっと簡潔な構文です。

35
FlySwat

これは、ラムダ式を使用する1つの方法です。あなたはラムダ式を使うことができますどこでもあなたはデリゲートを使うことができます。これにより、次のようなことができます。

List<string> strings = new List<string>();
strings.Add("Good");
strings.Add("Morning")
strings.Add("Starshine");
strings.Add("The");
strings.Add("Earth");
strings.Add("says");
strings.Add("hello");

strings.Find(s => s == "hello");

このコードはWordで "hello"と一致するエントリをリストから検索します。これを行うためのもう1つの方法は、実際には次のようにFindメソッドにデリゲートを渡すことです。

List<string> strings = new List<string>();
strings.Add("Good");
strings.Add("Morning")
strings.Add("Starshine");
strings.Add("The");
strings.Add("Earth");
strings.Add("says");
strings.Add("hello");

private static bool FindHello(String s)
{
    return s == "hello";
}

strings.Find(FindHello);

EDIT

C#2.0では、これは匿名のデリゲート構文を使って行うことができます。

  strings.Find(delegate(String s) { return s == "hello"; });

Lambdaはその構文を大幅に整理しました。

29
Scott Dorman

マイクロソフトは、Lambda式と呼ばれる匿名デリゲートを作成するためのよりクリーンでより便利な方法を私たちに提供しています。ただし、この文のの部分にはそれほど注意を払っていません。 Microsoftは、名前空間全体 System.Linq.Expressions をリリースしました。これには、ラムダ式に基づいて式ツリーを作成するためのクラスが含まれています。式ツリーは、ロジックを表すオブジェクトで構成されています。たとえば、x = y + zは、.NETの式ツリーの一部になる可能性がある式です。次の(単純な)例を考えてください。

using System;
using System.Linq;
using System.Linq.Expressions;


namespace ExpressionTreeThingy
{
    class Program
    {
        static void Main(string[] args)
        {
            Expression<Func<int, int>> expr = (x) => x + 1; //this is not a delegate, but an object
            var del = expr.Compile(); //compiles the object to a CLR delegate, at runtime
            Console.WriteLine(del(5)); //we are just invoking a delegate at this point
            Console.ReadKey();
        }
    }
}

この例は簡単です。また、「式を作成して実行時にコンパイルするのではなく、デリゲートを直接作成することもできたので、これは役に立ちません」とあなたは考えていると思います。そしてあなたは正しいでしょう。しかし、これが式ツリーの基盤となります。式の名前空間にはいくつかの式がありますが、独自に作成することもできます。設計時またはコンパイル時にアルゴリズムがどのようなものであるべきか正確にはわからない場合は、これが役立つことがあると思います。私はこれを使って電卓を書くための例をどこかに見ました。 ベイジアン システム、または 遺伝的プログラミング (AI)にも使用できます。私のキャリアの中で何度か私は利用可能なデータを操作するためにユーザーが簡単な表現(足し算、引き算など)を入力することを可能にするExcelのような機能を書かなければなりませんでした。 .NET 3.5より前のバージョンでは、C#の外部のスクリプト言語に頼らなければならなかったか、または.Netコードをその場で作成するためにコード発行機能を使用しなければなりませんでした。今度は式ツリーを使用します。

22
Jason Jackson

特定の場所で一度だけ使用されるメソッドを、それらが使用される場所から遠く離れて定義されていないようにする必要がなくなります。ソートなどの一般的なアルゴリズムの比較子として使用するとよいでしょう。ソートを呼び出している場所でカスタムソート関数を定義して、ソート先を確認するために他の場所を探す必要がなくなります。

そしてそれは本当に技術革新ではありません。 LISPは約30年以上にわたってラムダ関数を持っています。

12
workmad3

ラムダ式はデリゲートインスタンスの代わりに書かれた無名メソッドのようなものです。

delegate int MyDelagate (int i);
MyDelagate delSquareFunction = x => x * x;

ラムダ式x => x * x;を考えます

入力パラメーター値はx(=>の左側)です。

関数ロジックはx * x(=>の右側)です。

ラムダ式のコードは式ではなくステートメントブロックにすることができます。

x => {return x * x;};

注:Funcは、事前定義された総称デリゲートです。

    Console.WriteLine(MyMethod(x => "Hi " + x));

    public static string MyMethod(Func<string, string> strategy)
    {
        return strategy("Lijo").ToString();
    }

参考文献

  1. どのようにデリゲートとインターフェースを同じ意味で使用できますか?
6
Lijo

あなたのメソッドに作用する一般的なコードを書く際にラムダ式を使うこともできます。

例:メソッド呼び出しにかかる時間を計算するための汎用関数。 (つまり、ここではAction

public static long Measure(Action action)
{
    Stopwatch sw = new Stopwatch();
    sw.Start();
    action();
    sw.Stop();
    return sw.ElapsedMilliseconds;
}

そして、以下のようにラムダ式を使って上記のメソッドを呼び出すことができます。

var timeTaken = Measure(() => yourMethod(param));

式を使用すると、メソッドから戻り値を取得したり、パラメータを取得したりすることができます。

var timeTaken = Measure(() => returnValue = yourMethod(param, out outParam));
6
Gunasekaran

多くの場合、1つの場所で機能を使用しているだけなので、メソッドを作成するとクラスが散らかってしまいます。

4
Darren Kopp

ラムダ式は、無名メソッドを表すための簡潔な方法です。無名メソッドとLambda式のどちらでもメソッド実装をインラインで定義できますが、無名メソッドでは明示的にメソッドのパラメータ型と戻り型を定義する必要があります。ラムダ式では、C#3.0の型推論機能を使用しているため、コンパイラはコンテキストに基づいて変数の型を推論できます。入力する手間が省けるので、とても便利です。

4
Vijesh VP

これは、小さな操作を行い、それが使用される場所に非常に近づけるための方法です(変数をその使用点の近くで宣言するのとは異なります)。これはあなたのコードをもっと読みやすくするためのものです。式を匿名化することによって、関数が他の場所で使用されて「拡張」するように変更されている場合、クライアントコードを誰かが解読することが非常に困難になります。

同様に、なぜあなたはforeachを使う必要があるのですか?あなたは単純なforループまたは直接IEnumerableを直接使ってforeachですべてをすることができます。答:あなたはそうではありません必要それはあなたのコードを読みやすくします。

3
plinth

これはおそらくラムダ式を使う理由についての最も良い説明です - > https://youtu.be/j9nj5dTo54Q

要約すると、コードの読みやすさを向上させ、コードを複製するのではなく再利用することでエラーの可能性を減らし、舞台裏で行われている最適化を活用することです。

0
coffeeeee

イノベーションはタイプの安全性と透明性にあります。ラムダ式の型は宣言しませんが、それらは推論され、コード検索、静的分析、リファクタリングツール、およびランタイムリフレクションで使用できます。

たとえば、SQLを使用したことがあり、SQLインジェクション攻撃を受ける可能性がある前は、ハッカーが数字が通常予想される場所に文字列を渡したためです。これで保護されているLINQラムダ式を使用します。

評価前に式ツリーを結合する必要があるため、純粋なデリゲートでLINQ APIを構築することは不可能です。

2016年には、ほとんどの一般的な言語が ラムダ式 をサポートし、C#は主流の命令型言語の中でこの進化の先駆者の1人でした。

0
battlmonstr