Frage

Ich habe schnell über das gelesen Microsoft Lambda Ausdruck Dokumentation.

Diese Art von Beispiel hat mir jedoch geholfen, besser zu verstehen:

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

Trotzdem verstehe ich nicht, warum es eine solche Innovation ist. Es ist nur eine Methode, die stirbt, wenn die "Methodenvariable" endet, oder? Warum sollte ich das anstelle einer echten Methode verwenden?

War es hilfreich?

Lösung

Lambda -Ausdrücke sind eine einfachere Syntax für anonyme Delegierte und können überall verwendet werden, wo ein anonymer Delegat verwendet werden kann. Das Gegenteil ist jedoch nicht wahr; Lambda -Ausdrücke können in Expressionsbäume umgewandelt werden, die viel Magie wie Linq zu SQL ermöglichen.

Das Folgende ist ein Beispiel für a Linq zu Objekten Ausdruck mit anonymen Delegierten dann Lambda -Ausdrücke, um zu zeigen, wie viel einfacher sie auf dem Auge sind:

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

Lambda -Ausdrücke und anonyme Delegierte haben einen Vorteil gegenüber dem Schreiben einer separaten Funktion: Sie implementieren Schließungen das kann es Ihnen ermöglichen Übergeben Sie den lokalen Zustand an die Funktion, ohne Parameter hinzuzufügen zur Funktion oder Erstellen von Einsternungsobjekten.

Ausdruck von Bäumen sind ein sehr leistungsstarkes neues Merkmal von C# 3.0, mit dem eine API die Struktur eines Ausdrucks betrachtet, anstatt nur einen Verweis auf eine Methode zu erhalten, die ausgeführt werden kann. Eine API muss nur einen Delegiertenparameter in eine machen Expression<T> Parameter und der Compiler erzeugen einen Ausdrucksbaum aus einem Lambda anstelle eines anonymen Delegiertens:

void Example(Predicate<int> aDelegate);

genannt wie:

Example(x => x > 5);

wird:

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

Letzteres wird eine Darstellung des Zusammenfassung Syntaxbaum das beschreibt den Ausdruck x > 5. LINQ zu SQL ist auf dieses Verhalten angewiesen, um C# Ausdrücke in die SQL -Ausdrücke zu wenden, um auf der Serverseite zu filtern / usw. zu filtern / usw.

Andere Tipps

Anonyme Funktionen und Ausdrücke sind nützlich für einmalige Methoden, die nicht von der zusätzlichen Arbeit profitieren, die für die Erstellung einer vollständigen Methode erforderlich ist.

Betrachten Sie dieses Beispiel:

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

gegen

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

Diese sind funktionell äquivalent.

Ich fand sie in einer Situation nützlich, als ich einen Handler für das Ereignis einiger Kontrolle erklären wollte. Zu diesem Normalerweise müssten Sie die Referenzen der Kontrollen in Feldern der Klasse speichern, damit Sie sie in einer anderen Methode verwenden können als sie erstellt wurden.

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

Vielen Dank an Lambda -Ausdrücke können Sie wie folgt verwenden:

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

Viel einfacher.

Lambdas reinigte C# 2.0 -Anonyme Delegate -Syntax ... zum Beispiel

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

Wurde in C# 2.0 wie folgt gemacht:

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

Funktionell tun sie genau das Gleiche, es ist nur eine viel prägnantere Syntax.

Dies ist nur eine Möglichkeit, einen Lambda -Ausdruck zu verwenden. Sie können einen Lambda -Ausdruck verwenden irgendwo Sie können einen Delegierten verwenden. Auf diese Weise können Sie solche Dinge tun:

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

Dieser Code sucht die Liste nach einem Eintrag, der mit dem Wort "Hallo" übereinstimmt. Die andere Möglichkeit, dies zu tun, besteht darin, einen Delegierten an die Find -Methode wie folgt zu übergeben:

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

BEARBEITEN:

In C# 2.0 könnte dies mit der anonymen Delegierten -Syntax erfolgen:

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

Lambda hat diese Syntax erheblich aufgeräumt.

Microsoft hat uns eine sauberere und bequemere Möglichkeit gegeben, anonyme Delegierte als Lambda -Ausdrücke zu erstellen. Es wird jedoch nicht viel Aufmerksamkeit an die geschenkt Ausdrücke Teil dieser Aussage. Microsoft veröffentlichte einen ganzen Namespace, System.linq.expressions, die Klassen enthält, um Ausdrucksbäume zu erstellen, die auf Lambda -Ausdrücken basieren. Ausdrucksbäume bestehen aus Objekten, die Logik darstellen. Zum Beispiel ist x = y + z ein Ausdruck, der Teil eines Ausdrucksbaums in .NET sein könnte. Betrachten Sie das folgende (einfache) Beispiel:

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

Dieses Beispiel ist trivial. Und ich bin sicher, Sie denken: "Das ist nutzlos, da ich den Delegierten direkt hätte erstellen können, anstatt einen Ausdruck zu erstellen und zur Laufzeit zu kompilieren." Und du hättest Recht. Dies bildet jedoch die Grundlage für Ausdrucksbäume. Es gibt eine Reihe von Ausdrücken in den Namensspitzen aus dem Ausdruck, und Sie können Ihre eigenen erstellen. Ich denke, Sie können sehen, dass dies möglicherweise nützlich ist, wenn Sie nicht genau wissen, was der Algorithmus in der Gestaltung oder zum Kompilieren der Zeit sein soll. Ich habe irgendwo ein Beispiel dafür gesehen, dass ich einen wissenschaftlichen Taschenrechner schreibe. Sie könnten es auch für verwenden Bayesian Systeme oder für Genetische Programmierung (AI). Ein paar Mal in meiner Karriere musste ich Excel-ähnliche Funktionen schreiben, mit denen Benutzer einfache Ausdrücke (Zugabe, Untertrationen usw.) eingeben konnten, um verfügbare Daten zu betreiben. In Pre -.Net 3.5 musste ich auf eine Skriptsprache extern, die extern zu C#ist, oder die Code-emittierende Funktionen in Reflexion verwenden musste, um .NET-Code im laufenden Fliegen zu erstellen. Jetzt würde ich Ausdrucksbäume verwenden.

Es rettet, dass sie Methoden haben, die nur einmal an einem bestimmten Ort verwendet werden, weil sie weit weg von dem Ort definiert werden, an dem sie verwendet werden. Gute Verwendungszwecke sind als Vergleiche für generische Algorithmen wie Sortieren, bei denen Sie dann eine benutzerdefinierte Sortierfunktion definieren können, bei der Sie die Sortierung anrufen, anstatt Sie weiter zu zwingen, anderswo zu suchen, um zu sehen, was Sie sortieren.

Und es ist nicht wirklich eine Innovation. LISP hat seit etwa 30 Jahren Lambda -Funktionen.

Ein Lambda -Ausdruck ist wie eine anonyme Methode, die anstelle einer Delegierteninstanz geschrieben wurde.

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

Betrachten Sie den Lambda -Ausdruck x => x * x;

Der Eingabeparameterwert beträgt x (auf der linken Seite von =>)

Die Funktionslogik ist x * x (auf der rechten Seite von =>)

Der Code eines Lambda -Ausdrucks kann ein Anweisungsblock anstelle eines Ausdrucks sein.

x => {return x * x;};

Beispiel

Notiz: Func ist ein vordefinierter generischer Delegierter.

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

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

Verweise

  1. Wie kann ein Delegat und eine Schnittstelle austauschbar verwendet werden?

Sie können auch die Verwendung von Lambda -Ausdrücken beim Schreiben von generischen Codes finden, um auf Ihre Methoden zu reagieren.

Zum Beispiel: Generische Funktion zur Berechnung der Zeit, die durch einen Methodenaufruf benötigt wurde. (dh Action hier drin)

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

Und Sie können die obige Methode mit dem Lambda -Ausdruck wie folgt aufrufen.

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

Mit dem Ausdruck können Sie auch den Rückgabewert von Ihrer Methode und Ihrem Paramerium erhalten

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

A lot of the times, you are only using the functionality in one place, so making a method just clutters up the class.

Lambda expression is a concise way to represent an anonymous method. Both anonymous methods and Lambda expressions allow you define the method implementation inline, however, an anonymous method explicitly requires you to define the parameter types and the return type for a method. Lambda expression uses the type inference feature of C# 3.0 which allows the compiler to infer the type of the variable based on the context. It’s is very convenient because that saves us a lot of typing!

It's a way of taking small operation and putting it very close to where it is used (not unlike declaring a variable close to its use point). This is supposed to make your code more readable. By anonymizing the expression, you're also making it a lot harder for someone to break your client code if it the function is used somewhere else and modified to "enhance" it.

Similarly, why do you need to use foreach? You can do everything in foreach with a plain for loop or just using IEnumerable directly. Answer: you don't need it but it makes your code more readable.

The innovation is in the type safety and transparency. Although you don't declare types of lambda expressions, they are inferred, and can be used by code search, static analysis, refactoring tools, and runtime reflection.

For example, before you might have used SQL and could get an SQL injection attack, because a hacker passed a string where a number was normally expected. Now you would use a LINQ lambda expression, which is protected from that.

Building a LINQ API on pure delegates is not possible, because it requires combining expression trees together before evaluating them.

In 2016 most of the popular languages have lambda expression support, and C# was one of the pioneers in this evolution among the mainstream imperative languages.

This is perhaps the best explanations on why to use lambda expressions -> https://youtu.be/j9nj5dTo54Q

In summary, it's to improve code readability, reduce chances of errors by reusing rather than replicating code, and leverage optimization happening behind the scenes.

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top