it-swarm.dev

C # Lambda výrazy: Proč bych je měl používat?

Rychle jsem si přečetl dokumentaci Microsoft Lambda Expression .

Tento příklad mi pomohl lépe porozumět: 

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

Přesto nechápu, proč je to taková inovace. Je to jen metoda, která umírá, když končí "proměnná metody", že? Proč bych to měl použít namísto skutečné metody?

290

Lambda výrazy jsou jednodušší syntaxí pro anonymní delegáty a mohou být použity všude, kde může být použit anonymní delegát. Opak však není pravdivý; lambda výrazy mohou být převedeny na výrazové stromy, což umožňuje spoustu magie jako LINQ to SQL. 

Níže je uveden příklad výrazu LINQ to Objects /, který používá anonymní delegáty a pak výrazy lambda, které ukazují, jak mnohem jednodušší jsou na oku:

// 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();

Výrazy Lambda a anonymní delegáti mají výhodu oproti zápisu samostatné funkce: implementují uzávěry které vám umožní předat místní stav do funkce bez přidání parametrů do funkce nebo vytváření objektů pro jednorázové použití .

Stromy výrazů jsou velmi silnou novinkou funkce C # 3.0, která umožňuje rozhraní API podívat se na strukturu výrazu namísto získání odkazu na metodu, kterou lze provést. Rozhraní API musí pouze zadat parametr delegate do parametru Expression<T> a kompilátor vygeneruje strom výrazu z lambda namísto anonymního delegáta:

void Example(Predicate<int> aDelegate);

volal jako:

Example(x => x > 5);

se stává:

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

Ten bude mít předán reprezentaci abstraktního stromu syntaxe , který popisuje výraz x > 5. LINQ to SQL spoléhá na toto chování, aby bylo možné převést výrazy C # na výrazy SQL požadované pro filtrování/objednávání/atd. Na straně serveru.

270
Neil Williams

Anonymní funkce a výrazy jsou užitečné pro jednorázové metody, které nevyužívají dodatečné práce potřebné k vytvoření úplné metody.

Zvažte tento příklad:

 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;
 }

Ty jsou funkčně rovnocenné.

133
Joseph Daigle

Zjistil jsem, že jsou užitečné v situaci, kdy jsem chtěl deklarovat handler pro nějakou událost kontroly, pomocí jiné kontroly. Aby to bylo normálně, museli byste ukládat odkazy na ovládací prvky v polích třídy, abyste mohli používat jiným způsobem, než byly vytvořeny.

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;
}

díky výrazům lambda jej můžete použít takto:

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

Mnohem snazší.

83
agnieszka

Lambda vyčistila syntaxi anonymního delegáta C # 2.0 ... například

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

Bylo provedeno v jazyce C # 2.0 takto:

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

Funkčně dělají přesně to samé, jeho pouhá stručná syntaxe.

35
FlySwat

To je jen jeden způsob, jak použít lambda výraz. Můžete použít lambda výraz kdekoli můžete použít delegáta. To vám umožní dělat takovéto věci:

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");

Tento kód bude prohledávat seznam položek, které odpovídají slovu "hello". Druhým způsobem, jak toho dosáhnout, je skutečně předat delegát metodě Najít, jako je tato:

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);

UPRAVIT:

V jazyce C # 2.0 to lze provést pomocí syntaxe anonymního delegáta:

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

Lambda tuto syntaxi výrazně vyčistila.

29
Scott Dorman

Microsoft nám dal čistší a pohodlnější způsob vytváření anonymních delegátů, kteří se nazývají výrazy Lambda. Není však mnoho pozornosti věnováno části výrazů tohoto prohlášení. Microsoft vydal celý jmenný prostor, System.Linq.Expressions , který obsahuje třídy pro vytvoření výrazových stromů na základě výrazů lambda. Stromy výrazů jsou tvořeny objekty, které představují logiku. Například x = y + z je výraz, který může být součástí stromu výrazu v .Net. Zvažte následující (jednoduchý) příklad:

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();
        }
    }
}

Tento příklad je triviální. A jsem si jistý, že přemýšlíte: "Je to zbytečné, protože jsem mohl přímo vytvořit delegáta namísto vytvoření výrazu a jeho kompilace za běhu". A měli byste pravdu. To však poskytuje základ pro výrazové stromy. V jmenných prostorech výrazů je k dispozici několik výrazů a můžete si vytvořit vlastní. Myslím, že můžete vidět, že to může být užitečné, když přesně nevíte, co by měl algoritmus být v době návrhu nebo kompilace. Někde jsem viděl příklad, jak to udělat, abych napsal vědeckou kalkulačku. Můžete také použít pro Bayesovské systémy, nebo pro genetické programování (AI). Párkrát v mé kariéře jsem musel psát funkce podobné Excelu, které umožnily uživatelům zadávat jednoduché výrazy (sčítání, podtržení atd.), Aby mohli pracovat s dostupnými daty. V pre-.Net 3.5 jsem se musel uchýlit k některému skriptovacímu jazyku, který je mimo C #, nebo musel použít funkci vyzařující kód v odrazu, abych vytvořil kód sítě .Net za běhu. Teď bych použil výrazové stromy. 

21
Jason Jackson

Šetří tak, že musejí mít metody, které jsou používány pouze jednou na určitém místě před definováním daleko od místa, kde jsou používány. Dobrá použití jsou jako komparátory pro obecné algoritmy, jako je například třídění, kde pak můžete definovat vlastní třídicí funkci, kde vyvoláváte druh, spíše než dál, což vás nutí hledat jinde, abyste viděli, co si třídíte.

A není to opravdu inovace. LISP měl lambda funkce pro asi 30 roků nebo více.

12
workmad3

Výraz lambda je jako anonymní metoda napsaná namísto instance delegáta.

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

Zvažte výraz lambda x => x * x;

Hodnota vstupního parametru je x (na levé straně =>)

Funkční logika je x * x (na pravé straně =>)

Kód výrazu lambda může být namísto výrazu blokem příkazu. 

x => {return x * x;};

Příklad

Poznámka: Func je předdefinovaný generický delegát.

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

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

Reference

  1. Jak může být delegát & rozhraní používán zaměnitelně?
6
Lijo

Můžete také najít použití výrazů lambda při psaní obecných kódů, abyste mohli postupovat podle svých metod.

Například: Obecná funkce pro výpočet času volaného voláním metody. (tj. Action zde)

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

A výše uvedenou metodu můžete nazvat pomocí lambda výrazu takto:

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

Výraz umožňuje získat návratovou hodnotu z vaší metody a také z param

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

Hodně času, používáte pouze funkce na jednom místě, takže dělat metodu jen zmatky ve třídě.

4
Darren Kopp

Výraz Lambda je výstižným způsobem, jak reprezentovat anonymní metodu. Anonymní metody i výrazy Lambda umožňují definovat inline implementaci metody, nicméně anonymní metoda výslovně vyžaduje definování typů parametrů a typu návratu pro metodu. Výraz Lambda používá funkci odvození typu C # 3.0, která umožňuje kompilátoru odvodit typ proměnné na základě kontextu. Je to velmi pohodlné, protože nám to ušetří spoustu psaní!

4
Vijesh VP

Je to způsob, jak vzít malou operaci a dát ji velmi blízko tam, kde se používá (ne na rozdíl od deklarování proměnné v blízkosti jejího bodu použití). Předpokládá se, že kód bude lépe čitelný. Anonymizací výrazu také děláte, že je pro někoho mnohem těžší prolomit váš klientský kód, pokud je funkce používána někde jinde a upravena tak, aby ji "vylepšila".

Proč je třeba použít foreach? Můžete dělat vše v foreach s rovinou pro smyčku nebo jen pomocí IEnumerable přímo. Odpověď: nemusíte potřebujete ale to dělá váš kód lépe čitelný.

3
plinth

Toto je možná nejlepší vysvětlení, proč používat výrazy lambda -> https://youtu.be/j9nj5dTo54Q

Stručně řečeno, je to pro zlepšení čitelnosti kódu, snížení pravděpodobnosti chyb opakovaným použitím, nikoli pro replikaci kódu, a optimalizace pákového efektu, která se odehrává v zákulisí. 

0
coffeeeee

Inovace je v oblasti bezpečnosti a transparentnosti. I když neuvádíte typy výrazů lambda, jsou odvozeny a lze je použít při vyhledávání kódu, statické analýze, nástrojích refactoring a runtime reflexi.

Například předtím, než jste mohli použít SQL a mohli získat SQL injekční útok, protože hacker předal řetězec, kde se obvykle očekávalo číslo. Nyní byste měli použít výraz LINQ lambda, který je před tím chráněn.

Vytvoření rozhraní LINQ API na čistých delegátech není možné, protože před jejich vyhodnocováním je nutné kombinovat stromy výrazů.

V roce 2016 většina populárních jazyků má lambda výraz podpora, a C # byl jeden z průkopníků v tomto vývoji mezi hlavní proudové imperativní jazyky.

0
battlmonstr