Freigeben über


Lambdaausdrücke und anonyme Funktionen

Sie verwenden einen Lambdaausdruck, um eine anonyme Funktion zu erstellen. Verwenden Sie den Lambdadeklarationsoperator =>, um die Parameterliste des Lambdas von dessen Text zu trennen. Ein Lambdaausdruck kann eine der folgenden beiden Formen aufweisen:

  • Ein Ausdruckslambda mit einem Ausdruck als Text:

    (input-parameters) => expression
    
  • Ein Anweisungslambda mit einem Anweisungsblock als Text:

    (input-parameters) => { <sequence-of-statements> }
    

Geben Sie zum Erstellen eines Lambdaausdrucks Eingabeparameter (falls vorhanden) auf der linken Seite des Lambdaoperators und einen Ausdruck oder Anweisungsblock auf der anderen Seite an.

Jeder Lambdaausdruck kann in einen Delegat-Typ konvertiert werden. Die Typen der Parameter und der Rückgabewert definieren den Delegattyp, in den ein Lambda-Ausdruck konvertiert werden kann. Wenn ein Lambdaausdruck keinen Wert zurückgibt, kann er in einen der Action-Delegattypen konvertiert werden. Andernfalls kann er in einen der Func-Delegattypen konvertiert werden. Ein Lambdaausdruck, der beispielsweise zwei Parameter hat und keinen Wert zurückgibt, kann in einen Action<T1,T2>-Delegat konvertiert werden. Außerdem kann ein Lambdaausdruck, der einen Parameter hat und einen Wert zurückgibt, in einen Func<T,TResult>-Delegat konvertiert werden. Im folgenden Beispiel wird der Lambdaausdruck x => x * x, der einen Parameter x angibt und den Wert von x im Quadrat zurückgibt, einer Variablen eines Delegattyps zugewiesen:

Func<int, int> square = x => x * x;
Console.WriteLine(square(5));
// Output:
// 25

Zudem lassen sich Ausdruckslambdas in Ausdrucksbaumstruktur-Typen konvertieren, wie im folgenden Beispiel gezeigt:

System.Linq.Expressions.Expression<Func<int, int>> e = x => x * x;
Console.WriteLine(e);
// Output:
// x => (x * x)

Sie verwenden Lambdaausdrücke in jedem Code, der Instanzen von Delegattypen oder Ausdrucksstrukturen erfordert. Ein Beispiel ist das Argument für die Task.Run(Action)-Methode, um den Code zu übergeben, der im Hintergrund ausgeführt werden soll. Wie im folgenden Beispiel gezeigt wird, können Sie beim Schreiben von LINQ in C# auch Lambdaausdrücke verwenden:

int[] numbers = { 2, 3, 4, 5 };
var squaredNumbers = numbers.Select(x => x * x);
Console.WriteLine(string.Join(" ", squaredNumbers));
// Output:
// 4 9 16 25

Wenn Sie zum Aufrufen der Enumerable.Select-Methode in der System.Linq.Enumerable-Klasse methodenbasierte Syntax verwenden, wie in LINQ to Objects und LINQ to XML, ist der Parameter ein Delegattyp System.Func<T,TResult>. Wenn Sie die Queryable.Select-Methode in der System.Linq.Queryable-Klasse aufrufen, wie in LINQ to SQL, ist der Parametertyp ein Ausdrucksbaumstruktur-Typ Expression<Func<TSource,TResult>>. In beiden Fällen können Sie denselben Lambdaausdruck verwenden, um die Parameterwerte anzugeben. Dadurch sehen die Select-Aufrufe ähnlich aus, obwohl sich der mithilfe der Lambdas erstellte Objekttyp unterscheidet.

Ausdruckslambdas

Ein Lambdaausdruck mit einem Ausdruck auf der rechten Seite des =>-Operators wird als Ausdruckslambda bezeichnet. Ein Ausdruckslambda gibt das Ergebnis des Ausdrucks zurück und hat folgende grundlegende Form:

(input-parameters) => expression

Der Text eines Ausdruckslambdas kann aus einem Methodenaufruf bestehen. Wenn Sie jedoch Ausdrucksbaumstrukturen erstellen, die außerhalb des Kontexts der .NET Common Language Runtime (CLR) ausgewertet werden, z. B. in SQL Server, sollten Sie in Lambdaausdrücken keine Methodenaufrufe verwenden. Die Methoden haben außerhalb des Kontexts der .NET Common Language Runtime (CLR) keine Bedeutung.

Anweisungslambdas

Ein Anweisungslambda ähnelt einem Ausdruckslambda, allerdings sind die Anweisungen in Klammern eingeschlossen:

(input-parameters) => { <sequence-of-statements> }

Der Text eines Anweisungslambdas kann aus einer beliebigen Anzahl von Anweisungen bestehen, wobei es sich meistens um höchstens zwei oder drei Anweisungen handelt.

Action<string> greet = name =>
{
    string greeting = $"Hello {name}!";
    Console.WriteLine(greeting);
};
greet("World");
// Output:
// Hello World!

Anweisungslambdas können nicht zum Erstellen von Ausdrucksbaumstrukturen verwendet werden.

Eingabeparameter eines Lambdaausdrucks

Sie schließen die Eingabeparameter eines Lambdaausdrucks in Klammern ein. Geben Sie Eingabeparameter von 0 (null) mit leeren Klammern an:

Action line = () => Console.WriteLine();

Wenn ein Lambdaausdruck nur über einen Eingabeparameter verfügt, sind Klammern optional:

Func<double, double> cube = x => x * x * x;

Zwei oder mehr Eingabeparameter werden durch Kommas getrennt:

Func<int, int, bool> testForEquality = (x, y) => x == y;

Manchmal kann der Compiler die Typen von Eingabeparametern nicht ableiten. Sie können die Typen wie im folgenden Beispiel dargestellt explizit angeben:

Func<int, string, bool> isTooLong = (int x, string s) => s.Length > x;

Eingabeparametertypen müssen alle entweder explizit oder implizit sein. Andernfalls tritt der Compilerfehler CS0748 auf.

Sie können discards verwenden, um mindestens zwei Eingabeparameter eines Lambdaausdrucks anzugeben, der nicht im Ausdruck verwendet wird:

Func<int, int, int> constant = (_, _) => 42;

Verwerfungsparameter von Lambdas können nützlich sein, wenn Sie einen Lambdaausdruck zur Bereitstellung eines Ereignishandlers verwenden.

Hinweis

Aus Gründen der Abwärtskompatibilität wird innerhalb eines Lambdaausdrucks _ als Name des Parameters behandelt, wenn nur ein einzelner Eingabeparameter den Namen _ aufweist.

Ab C# 12 können Sie Standardwerte für Parameter für Lambdaausdrücke bereitstellen. Die Syntax und die Einschränkungen für Standardparameterwerte sind identisch mit denen für Methoden und lokale Funktionen. Im folgenden Beispiel wird ein Lambdaausdruck mit einem Standardparameter deklariert und dann einmal mit dem Standard und einmal mit zwei expliziten Parametern aufgerufen:

var IncrementBy = (int source, int increment = 1) => source + increment;

Console.WriteLine(IncrementBy(5)); // 6
Console.WriteLine(IncrementBy(5, 2)); // 7

Sie können Lambdaausdrücke auch mit params-Arrays oder -Sammlungen als Parameter deklarieren:

var sum = (params IEnumerable<int> values) =>
{
    int sum = 0;
    foreach (var value in values) 
        sum += value;
    
    return sum;
};

var empty = sum();
Console.WriteLine(empty); // 0

var sequence = new[] { 1, 2, 3, 4, 5 };
var total = sum(sequence);
Console.WriteLine(total); // 15

Im Rahmen dieser Updates verfügt dieser Lambdaausdruck auch über den gleichen Standardparameter, wenn eine Methodengruppe mit einem Standardparameter einem Lambdaausdruck zugewiesen wird. Eine Methodengruppe mit einem params-Sammlungsparameter kann auch einem Lambdaausdruck zugewiesen werden.

Lambdaausdrücke mit Standardparametern oder params-Sammlungen als Parameter verfügen nicht über natürliche Typen, die Func<>- oder Action<>-Typen entsprechen. Sie können jedoch Delegatentypen definieren, die Standardwerte enthalten:

delegate int IncrementByDelegate(int source, int increment = 1);
delegate int SumDelegate(params int[] values);
delegate int SumCollectionDelegate(params IEnumerable<int> values);

Alternativ können Sie implizit typisierte Variablen mit var-Deklarationen verwenden, um den Delegattyp zu definieren. Der Compiler synthetisiert den richtigen Delegatentyp.

Weitere Informationen zu Standardparametern in Lambdaausdrücken finden Sie in der Featurespezifikation für Standardparameter für Lambdaausdrücke.

Asynchrone Lambdas

Sie können mit den Schlüsselwörtern async und await Lambda-Ausdrücke und Anweisungen, die asynchrone Verarbeitung enthalten, leicht erstellen. Das folgende Windows Forms enthält z. B. einen Ereignishandler, der eine Async-Methode, ExampleMethodAsync, aufruft und erwartet.

public partial class Form1 : Form
{
    public Form1()
    {
        InitializeComponent();
        button1.Click += button1_Click;
    }

    private async void button1_Click(object sender, EventArgs e)
    {
        await ExampleMethodAsync();
        textBox1.Text += "\r\nControl returned to Click event handler.\n";
    }

    private async Task ExampleMethodAsync()
    {
        // The following line simulates a task-returning asynchronous process.
        await Task.Delay(1000);
    }
}

Sie können denselben Ereignishandler hinzufügen, indem Sie ein asynchrones Lambda verwenden. Um diesen Handler hinzuzufügen, fügen Sie einen async-Modifizierer vor der Lambdaparameterliste hinzu, wie im folgenden Beispiel dargestellt:

public partial class Form1 : Form
{
    public Form1()
    {
        InitializeComponent();
        button1.Click += async (sender, e) =>
        {
            await ExampleMethodAsync();
            textBox1.Text += "\r\nControl returned to Click event handler.\n";
        };
    }

    private async Task ExampleMethodAsync()
    {
        // The following line simulates a task-returning asynchronous process.
        await Task.Delay(1000);
    }
}

Weitere Informationen zum Erstellen und Verwenden von asynchronen Methoden finden Sie unter Asynchronous programming with async and await (Asynchrones Programmieren mit „async“ and „await“).

Lambdaausdrücke und Tupel

Die Sprache C# bietet integrierte Unterstützung für Tupel. Sie können ein Tupel einem Lambdaausdruck als Argument bereitstellen, und Ihr Lambdaausdruck kann ebenfalls einen Tupel zurückgeben. In einigen Fällen verwendet der C#-Compiler den Typrückschluss, um den Typ der Tupelkomponenten zu ermitteln.

Sie können ein Tupel definieren, indem Sie eine durch Trennzeichen getrennte Liste seiner Komponenten in Klammern einschließen. In folgendem Beispiel wird ein Tupel mit drei Komponenten verwenden, um eine Zahlensequenz an einen Lambdaausdruck zu übergeben; dadurch wird jeder Wert verdoppelt, und es wird ein Tupel mit drei Komponenten zurückgegeben, das das Ergebnis der Multiplikation enthält.

Func<(int, int, int), (int, int, int)> doubleThem = ns => (2 * ns.Item1, 2 * ns.Item2, 2 * ns.Item3);
var numbers = (2, 3, 4);
var doubledNumbers = doubleThem(numbers);
Console.WriteLine($"The set {numbers} doubled: {doubledNumbers}");
// Output:
// The set (2, 3, 4) doubled: (4, 6, 8)

Für gewöhnlich heißen die Felder eines Tupels zum Beispiel Item1 oder Item2. Sie können allerdings ein Tupel mit benannten Komponenten definieren, wie in folgendem Beispiel veranschaulicht.

Func<(int n1, int n2, int n3), (int, int, int)> doubleThem = ns => (2 * ns.n1, 2 * ns.n2, 2 * ns.n3);
var numbers = (2, 3, 4);
var doubledNumbers = doubleThem(numbers);
Console.WriteLine($"The set {numbers} doubled: {doubledNumbers}");

Weitere Informationen zu C#-Tupeln finden Sie unter Tupeltypen.

Lambdas mit Standardabfrageoperatoren

Neben anderen Implementierungen weist auch LINQ to Objects einen Eingabeparameter auf, dessen Typ zur Func<TResult>-Familie generischer Delegate gehört. Diese Delegaten verwenden Typparameter zur Definition der Anzahl und des Typs der Eingabeparameter sowie des Rückgabetyps des Delegaten. Func-Delegaten sind für das Kapseln von benutzerdefinierten Ausdrücken nützlich, die für jedes Element in mehreren Quelldaten übernommen werden. Betrachten Sie z.B. den Func<T,TResult>-Delegattyp:

public delegate TResult Func<in T, out TResult>(T arg)

Der Delegat kann als Func<int, bool>-Instanz instanziiert werden, wobei int ein Eingabeparameter und bool der Rückgabewert ist. Der Rückgabewert wird immer im letzten Typparameter angegeben. Func<int, string, bool> definiert z.B. einen Delegaten mit zwei Eingabeparametern, int und string, und einen Rückgabetyp von bool. Der folgende Func-Delegat gibt bei einem Aufruf einen booleschen Wert zurück, um anzugeben, ob der Eingabeparameter gleich fünf ist:

Func<int, bool> equalsFive = x => x == 5;
bool result = equalsFive(4);
Console.WriteLine(result);   // False

Sie können einen Lambdaausdruck auch dann angeben, wenn der Argumenttyp Expression<TDelegate> ist, beispielsweise in den Standardabfrageoperatoren, die in Typ Queryable definiert sind. Wenn Sie ein Expression<TDelegate>-Argument angeben, wird der Lambdaausdruck in eine Ausdrucksbaumstruktur kompiliert.

Im folgenden Beispiel wird der Count-Standardabfrageoperator verwendet:

int[] numbers = { 5, 4, 1, 3, 9, 8, 6, 7, 2, 0 };
int oddNumbers = numbers.Count(n => n % 2 == 1);
Console.WriteLine($"There are {oddNumbers} odd numbers in {string.Join(" ", numbers)}");

Der Compiler kann den Typ des Eingabeparameters ableiten, Sie können ihn aber auch explizit angeben. Dieser bestimmte Lambda-Ausdruck zählt die ganzen Zahlen (n), bei denen nach dem Dividieren durch zwei als Rest 1 bleibt.

In folgendem Beispiel wird eine Sequenz erzeugt, die alle Elemente im Array numbers enthält, die vor der 9 auftreten, da dies die erste Zahl in der Sequenz ist, die die Bedingung nicht erfüllt:

int[] numbers = { 5, 4, 1, 3, 9, 8, 6, 7, 2, 0 };
var firstNumbersLessThanSix = numbers.TakeWhile(n => n < 6);
Console.WriteLine(string.Join(" ", firstNumbersLessThanSix));
// Output:
// 5 4 1 3

In folgendem Beispiel wird gezeigt, wie Sie mehrere Eingabeparameter angeben, indem Sie sie in Klammern einschließen. Mit der Methode werden alle Elemente im numbers-Array zurückgegeben, bis eine Zahl erreicht wird, deren Wert kleiner ist als ihre Ordnungspostion im Array:

int[] numbers = { 5, 4, 1, 3, 9, 8, 6, 7, 2, 0 };
var firstSmallNumbers = numbers.TakeWhile((n, index) => n >= index);
Console.WriteLine(string.Join(" ", firstSmallNumbers));
// Output:
// 5 4

Sie verwenden Lambdaausdrücke nicht direkt in Abfrageausdrücken, aber Sie können sie in Methodenaufrufen innerhalb von Abfrageausdrücken verwenden, wie das folgende Beispiel zeigt:

var numberSets = new List<int[]>
{
    new[] { 1, 2, 3, 4, 5 },
    new[] { 0, 0, 0 },
    new[] { 9, 8 },
    new[] { 1, 0, 1, 0, 1, 0, 1, 0 }
};

var setsWithManyPositives = 
    from numberSet in numberSets
    where numberSet.Count(n => n > 0) > 3
    select numberSet;

foreach (var numberSet in setsWithManyPositives)
{
    Console.WriteLine(string.Join(" ", numberSet));
}
// Output:
// 1 2 3 4 5
// 1 0 1 0 1 0 1 0

Typrückschluss in Lambdaausdrücken

Beim Schreiben von Lambdas müssen Sie oftmals keinen Typ für die Eingabeparameter angeben, da der Compiler den Typ auf der Grundlage des Lambdatexts, der Parametertypen und anderer Faktoren ableiten kann, wie in der C#-Programmiersprachenspezifikation beschrieben. Bei den meisten Standardabfrageoperatoren entspricht die erste Eingabe dem Typ der Elemente in der Quellsequenz. Beim Abfragen von IEnumerable<Customer> wird die Eingabevariable als Customer-Objekt abgeleitet, sodass Sie auf die zugehörigen Methoden und Eigenschaften zugreifen können:

customers.Where(c => c.City == "London");

Die allgemeinen Regeln für Typrückschlüsse bei Lambdas lauten wie folgt:

  • Der Lambda-Ausdruck muss dieselbe Anzahl von Parametern enthalten wie der Delegattyp.
  • Jeder Eingabeparameter im Lambda muss implizit in den entsprechenden Delegatparameter konvertiert werden können.
  • Der Rückgabewert des Lambdas (falls vorhanden) muss implizit in den Rückgabetyp des Delegaten konvertiert werden können.

Natürlicher Typ eines Lambdaausdrucks

Ein Lambdaausdruck an sich besitzt keinen Typ, da das allgemeine Typsystem kein eigenes Konzept „Lambdaausdruck“ aufweist. Manchmal ist es aber ganz praktisch, informell vom „Typ“ eines Lambdaausdrucks zu sprechen. Dieser informelle „Typ“ bezeichnet den Delegattyp oder den Expression-Typ, in den der Lambdaausdruck konvertiert wird.

Ab C# 10 kann ein Lambdaausdruck einen natürlichen Typ aufweisen. Anstatt die Deklaration eines Delegattyps wie Func<...> oder Action<...> für einen Lambdaausdruck zu erzwingen, kann der Compiler den Delegattyp aus dem Lambdaausdruck ableiten. Betrachten Sie beispielsweise die folgende Deklaration:

var parse = (string s) => int.Parse(s);

Der Compiler kann bestimmen, dass parse als Func<string, int> abgeleitet wird. Der Compiler wählt einen verfügbaren Func- oder Action-Delegaten aus, sofern ein geeigneter vorhanden ist. Andernfalls wird ein Delegattyp synthetisiert. Beispielsweise wird der Delegattyp synthetisiert, wenn der Lambdaausdruck ref-Parameter enthält. Wenn ein Lambdaausdruck einen natürlichen Typ aufweist, kann er einem weniger expliziten Typ zugewiesen werden, z. B. System.Object oder System.Delegate:

object parse = (string s) => int.Parse(s);   // Func<string, int>
Delegate parse = (string s) => int.Parse(s); // Func<string, int>

Methodengruppen (d. h. Methodennamen ohne Argumentlisten) mit genau einer Überladung haben einen natürlichen Typ:

var read = Console.Read; // Just one overload; Func<int> inferred
var write = Console.Write; // ERROR: Multiple overloads, can't choose

Wenn Sie System.Linq.Expressions.LambdaExpression einen Lambdaausdruck zuweisen oder System.Linq.Expressions.Expression und die Lambdafunktion über einen natürlichen Delegattyp verfügen, besitzt der Ausdruck den natürlichen Typ System.Linq.Expressions.Expression<TDelegate>, und der natürliche Delegattyp wird als Argument für den Typparameter verwendet:

LambdaExpression parseExpr = (string s) => int.Parse(s); // Expression<Func<string, int>>
Expression parseExpr = (string s) => int.Parse(s);       // Expression<Func<string, int>>

Nicht alle Lambdaausdrücke haben einen natürlichen Typ. Betrachten Sie hierzu die folgende Deklaration:

var parse = s => int.Parse(s); // ERROR: Not enough type info in the lambda

Der Compiler kann keinen Compilertyp für s ableiten. Wenn der Compiler keinen natürlichen Typ ableiten kann, müssen Sie den Typ deklarieren:

Func<string, int> parse = s => int.Parse(s);

Expliziter Rückgabetyp

In der Regel ist der Rückgabetyp eines Lambdaausdrucks offensichtlich und wird abgeleitet. Bei einigen Ausdrücken funktioniert dies jedoch nicht:

var choose = (bool b) => b ? 1 : "two"; // ERROR: Can't infer return type

Ab C# 10 können Sie den Rückgabetyp für einen Lambdaausdruck vor den Eingabeparametern angeben. Wenn Sie einen expliziten Rückgabetyp angeben, müssen Sie die Eingabeparameter in Klammern einschließen:

var choose = object (bool b) => b ? 1 : "two"; // Func<bool, object>

Attributes

Ab C# 10 können Sie einem Lambdaausdruck und seinen Parametern Attribute hinzufügen. Das folgende Beispiel zeigt, wie einem Lambdaausdruck Attribute hinzugefügt werden:

Func<string?, int?> parse = [ProvidesNullCheck] (s) => (s is not null) ? int.Parse(s) : null;

Sie können auch Attribute zu den Eingabeparametern oder dem Rückgabewert hinzufügen, wie das folgende Beispiel zeigt:

var concat = ([DisallowNull] string a, [DisallowNull] string b) => a + b;
var inc = [return: NotNullIfNotNull(nameof(s))] (int? s) => s.HasValue ? s++ : null;

Wie die vorangegangenen Beispiele zeigen, müssen Sie die Eingabeparameter in Klammern einschließen, wenn Sie einem Lambdaausdruck oder seinen Parametern Attribute hinzufügen.

Wichtig

Lambdaausdrücke werden über den zugrunde liegenden Delegattyp aufgerufen. Dies unterscheidet sich von Methoden und lokalen Funktionen. Die Invoke-Methode des Delegaten überprüft keine Attribute für den Lambdaausdruck. Attribute haben keine Auswirkungen, wenn der Lambdaausdruck aufgerufen wird. Attribute für Lambdaausdrücke sind für die Codeanalyse nützlich und können über Reflektion ermittelt werden. Eine Folge hiervon ist, dass System.Diagnostics.ConditionalAttribute nicht auf einen Lambdaausdruck angewendet werden kann.

Erfassen äußerer Variablen sowie des Variablenbereichs in Lambdaausdrücken

Lambdas können auf äußere Variablen verweisen. Diese äußeren Variablen sind diejenigen Variablen, die in der Methode, die den Lambdaausdruck definiert, oder in dem Typ, der den Lambdaausdruck enthält, im Bereich liegen. Variablen, die auf diese Weise erfasst werden, werden zur Verwendung in Lambda-Ausdrücken gespeichert, auch wenn die Variablen andernfalls außerhalb des Gültigkeitsbereichs liegen und an die Garbage Collection übergeben würden. Eine äußere Variable muss definitiv zugewiesen sein, bevor sie in einem Lambda-Ausdruck verwendet werden kann. Das folgende Beispiel veranschaulicht diese Regeln:

public static class VariableScopeWithLambdas
{
    public class VariableCaptureGame
    {
        internal Action<int>? updateCapturedLocalVariable;
        internal Func<int, bool>? isEqualToCapturedLocalVariable;

        public void Run(int input)
        {
            int j = 0;

            updateCapturedLocalVariable = x =>
            {
                j = x;
                bool result = j > input;
                Console.WriteLine($"{j} is greater than {input}: {result}");
            };

            isEqualToCapturedLocalVariable = x => x == j;

            Console.WriteLine($"Local variable before lambda invocation: {j}");
            updateCapturedLocalVariable(10);
            Console.WriteLine($"Local variable after lambda invocation: {j}");
        }
    }

    public static void Main()
    {
        var game = new VariableCaptureGame();

        int gameInput = 5;
        game.Run(gameInput);

        int jTry = 10;
        bool result = game.isEqualToCapturedLocalVariable!(jTry);
        Console.WriteLine($"Captured local variable is equal to {jTry}: {result}");

        int anotherJ = 3;
        game.updateCapturedLocalVariable!(anotherJ);

        bool equalToAnother = game.isEqualToCapturedLocalVariable(anotherJ);
        Console.WriteLine($"Another lambda observes a new value of captured variable: {equalToAnother}");
    }
    // Output:
    // Local variable before lambda invocation: 0
    // 10 is greater than 5: True
    // Local variable after lambda invocation: 10
    // Captured local variable is equal to 10: True
    // 3 is greater than 5: False
    // Another lambda observes a new value of captured variable: True
}

Die folgenden Regeln gelten für den Variablenbereich in Lambda-Ausdrücken:

  • Eine erfasste Variable wird erst dann an die Garbage Collection übergeben, wenn der darauf verweisende Delegat für die Garbage Collection geeignet ist.
  • Variablen, die in einem Lambdaausdruck eingeführt wurden, sind in der einschließenden Methode nicht sichtbar.
  • Ein Lambdaausdruck kann einen in-, ref- oder out-Parameter nicht direkt von der einschließenden Methode erfassen.
  • Eine return-Anweisung in einem Lambdaausdruck bewirkt keine Rückgabe durch die einschließende Methode.
  • Ein Lambdaausdruck darf keine goto-, break- oder continue-Anweisung enthalten, wenn das Ziel dieser Sprunganweisung außerhalb des Lambdaausdrucksblocks liegt. Eine Sprunganweisung darf auch nicht außerhalb des Lambdaausdrucksblocks sein, wenn das Ziel im Block ist.

Sie können den static-Modifizierer auf einen Lambdaausdruck anwenden, um zu verhindern, dass lokale Variablen oder der Instanzzustand versehentlich durch die Lambdafunktion erfasst werden:

Func<double, double> square = static x => x * x;

Ein statischer Lambdaausdruck kann keine lokalen Variablen oder den Instanzzustand aus einschließenden Bereichen erfassen, kann jedoch auf statische Member und Konstantendefinitionen verweisen.

C#-Sprachspezifikation

Weitere Informationen finden Sie im Abschnitt Anonyme Funktionsausdrücke der C#-Sprachspezifikation.

Weitere Informationen zu diesen Features finden Sie in den folgenden Featurevorschlägen:

Weitere Informationen