Microsoft Lambda Expressionのドキュメントをざっと読みました。
ただし、この種の例は、理解を深めるのに役立ちました。
delegate int del(int i);
del myDelegate = x => x * x;
int j = myDelegate(5); //j = 25
それでも、なぜこれが革新的なのか理解できません。「メソッド変数」が終了すると死ぬメソッドですよね?実際のメソッドの代わりにこれを使用する必要があるのはなぜですか?
Microsoft Lambda Expressionのドキュメントをざっと読みました。
ただし、この種の例は、理解を深めるのに役立ちました。
delegate int del(int i);
del myDelegate = x => x * x;
int j = myDelegate(5); //j = 25
それでも、なぜこれが革新的なのか理解できません。「メソッド変数」が終了すると死ぬメソッドですよね?実際のメソッドの代わりにこれを使用する必要があるのはなぜですか?
ラムダ式は、匿名デリゲートのより単純な構文であり、匿名デリゲートを使用できるあらゆる場所で使用できます。ただし、その逆は当てはまりません。ラムダ式は式ツリーに変換できるため、LINQ to SQL のような多くの魔法が可能になります。
以下は、匿名デリゲートを使用してからラムダ式を使用するLINQ to Objects式の例で、それらがどれほど簡単かを示しています。
// 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();
ラムダ式と匿名デリゲートには、個別の関数を記述するよりも利点があります。関数にパラメーターを追加したり、1 回限りのオブジェクトを作成したりせずに、ローカル状態を関数に渡すことができるクロージャーを実装します。
式ツリーは、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 式に変換できるようにします。
匿名の関数と式は、完全なメソッドを作成するために必要な追加作業の恩恵を受けない 1 回限りのメソッドに役立ちます。
次の例を検討してください。
List<string> people = new List<string> { "name1", "name2", "joe", "another name", "etc" };
string person = people.Find(person => person.Contains("Joe"));
対
public string FindPerson(string nameContains, List<string> persons)
{
foreach (string person in persons)
if (person.Contains(nameContains))
return person;
return null;
}
これらは機能的に同等です。
別のコントロールを使用して、あるコントロールのイベントのハンドラーを宣言したい状況で、それらが役立つことがわかりました。通常それを行うには、コントロールの参照をクラスのフィールドに格納して、それらが作成されたメソッドとは別のメソッドで使用できるようにする必要があります。
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;};
}
はるかに簡単です。
LambdaはC#2.0の匿名デリゲート構文をクリーンアップしました...たとえば
Strings.Find(s => s == "hello");
このようにC#2.0で行われました:
Strings.Find(delegate(String s) { return s == "hello"; });
機能的には、まったく同じことを行いますが、構文ははるかに簡潔です。
これは、ラムダ式を使用する 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");
このコードは、「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);
編集:
C# 2.0 では、匿名デリゲート構文を使用してこれを行うことができました。
strings.Find(delegate(String s) { return s == "hello"; });
Lambda はその構文を大幅にクリーンアップしました。
Microsoft は、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();
}
}
}
この例は簡単です。そして、「式を作成して実行時にコンパイルする代わりに、デリゲートを直接作成できたので、これは役に立たない」と考えていると思います。そして、あなたは正しいでしょう。しかし、これは式ツリーの基礎を提供します。Expressions 名前空間には多数の式があり、独自の式を作成できます。これは、設計時またはコンパイル時にアルゴリズムがどうあるべきか正確にわからない場合に役立つことがわかると思います。これを使用して関数電卓を作成する例をどこかで見ました。ベイジアンシステムや遺伝的プログラミングにも使用できます(AI)。私のキャリアの中で、利用可能なデータを操作するためにユーザーが単純な式 (加算、減算など) を入力できる Excel のような機能を作成する必要があったことが何度かありました。.Net 3.5 より前のバージョンでは、C# 以外のスクリプト言語を使用するか、リフレクションでコード生成機能を使用してその場で .Net コードを作成する必要がありました。ここで、式ツリーを使用します。
特定の場所で一度だけ使用されるメソッドを、使用される場所から遠く離れた場所で定義する必要がなくなります。良い使い方は、ソートなどの一般的なアルゴリズムのコンパレーターとして使用できます。この場合、ソート対象を確認するために別の場所を探す必要がなくなり、ソートを呼び出すカスタム ソート関数を定義できます。
そして、それは実際にはイノベーションではありません。LISP には、ラムダ関数が約 30 年以上あります。
ラムダ式は匿名メソッドを簡潔に表す方法です。匿名メソッドと Lambda 式の両方で、メソッドの実装をインラインで定義できますが、匿名メソッドでは、メソッドのパラメーターの型と戻り値の型を明示的に定義する必要があります。ラムダ式は、C# 3.0 の型推論機能を使用して、コンパイラがコンテキストに基づいて変数の型を推論できるようにします。入力の手間が省けるのでとても便利です!
ラムダ式は、デリゲート インスタンスの代わりに記述された匿名メソッドのようなものです。
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 か所でしか使用していないため、メソッドを作成するとクラスが乱雑になります。
これは、小さな操作を取り、それが使用される場所の非常に近くに配置する方法です (使用ポイントの近くで変数を宣言するのと同じです)。これにより、コードが読みやすくなります。式を匿名化することで、関数が別の場所で使用され、それを「拡張」するために変更された場合に、誰かがクライアント コードを壊すこともずっと難しくなります。
同様に、なぜ foreach を使用する必要があるのでしょうか。foreach では、単純な for ループを使用するか、IEnumerable を直接使用するだけですべてを実行できます。回答:必要ありませんが、コードが読みやすくなります。
イノベーションは、型の安全性と透明性にあります。ラムダ式の型は宣言しませんが、推論され、コード検索、静的分析、リファクタリング ツール、およびランタイム リフレクションで使用できます。
たとえば、SQL を使用して SQL インジェクション攻撃を受ける前に、ハッカーが通常は数字が必要な場所に文字列を渡したことが原因です。ここで、それから保護されている LINQ ラムダ式を使用します。
純粋なデリゲートで LINQ API を構築することはできません。評価する前に式ツリーを結合する必要があるためです。
2016 年には、人気のある言語のほとんどがラムダ式をサポートしており、C# は主流の命令型言語の中でこの進化の先駆者の 1 つでした。
ラムダ式と無名関数の最大の利点は、ライブラリ/フレームワークのクライアント (プログラマー) が、指定されたライブラリ/フレームワーク (LINQ、ASP.NET Core および他の多くの ) 通常の方法ではできない方法で。ただし、それらの強みは、1 人のアプリケーション プログラマーにとって明らかではなく、ライブラリー コードの動作を構成したい他のユーザーが後で使用するライブラリーを作成するプログラマー、またはライブラリーを使用するプログラマーにとって明らかです。したがって、ラムダ式を効果的に使用するコンテキストは、ライブラリ/フレームワークの使用/作成です。
また、これらは 1 回限りのコードを記述するため、コードが複雑になるクラスのメンバーである必要はありません。クラス オブジェクトの操作を構成するたびに、フォーカスが不明なクラスを宣言しなければならないことを想像してみてください。