Freigeben über


Lambda-Ausdrü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 Lambda-Ausdruck 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. Sie können auch Lambda-Ausdrücke verwenden, wenn Sie LINQ in C#-schreiben, wie im folgenden Beispiel gezeigt:

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 methodenbasierte Syntax verwenden, um die Enumerable.Select Methode in der System.Linq.Enumerable Klasse aufzurufen, z. B. in LINQ to Objects und LINQ to XML, ist der Parameter ein delegierter Typ 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 Lambda-Ausdruck verwenden, um den Parameterwert anzugeben. Dadurch sehen die beiden Select-Aufrufe ähnlich aus, obwohl der Objekttyp, der aus den Lambdas erstellt wird, unterschiedlich ist.

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 keine Bedeutung außerhalb des Kontexts der .NET Common Language Runtime (CLR).

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 null Eingabeparameter mit leeren Klammern an:

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

Wenn ein Lambda-Ausdruck 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 Eingabeparametertypen nicht ableiten. Sie können die Typen explizit angeben, wie im folgenden Beispiel gezeigt:

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

Eingabeparametertypen müssen entweder alle explizit oder alle implizit sein; andernfalls tritt ein CS0748-Compilerfehler 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.

Anmerkung

Für die Abwärtskompatibilität, wenn nur ein einzelner Eingabeparameter mit _benannt ist, wird _ innerhalb eines Lambda-Ausdrucks als Name dieses Parameters behandelt.

Ab C# 12 können Sie Standardwerte für Parameter für Lambdaausdrücke bereitstellen. Die Syntax und die Einschränkungen für Standardparameterwerte entsprechen den Methoden und lokalen 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.

Lambda-Ausdrücke mit Standardparametern oder params-Auflistungen als Parameter verfügen nicht über natürliche Typen, die den Func<>- oder Action<>-Typen entsprechen. Sie können jedoch Stellvertretungstypen definieren, die Standardparameterwerte 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 ganz einfach Lambda-Ausdrücke und -Anweisungen erstellen, die asynchrone Verarbeitung integrieren, indem Sie die Schlüsselwörter async und await verwenden. 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 Lambda-Parameterliste hinzu, wie das folgende Beispiel zeigt:

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 Typinferenz, um die Typen von Tupelkomponenten zu bestimmen.

Sie definieren ein Tupel, indem Sie eine durch Trennzeichen getrennte Liste der zugehörigen 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 jedoch wie im folgenden Beispiel ein Tupel mit benannten Komponenten definieren.

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, um Anzahl und Typ der Eingabeparameter sowie den Rückgabetyp des Delegaten zu definieren. 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 ist und bool der Rückgabewert ist. Der Rückgabewert wird immer im letzten Typparameter angegeben. Beispielsweise definiert Func<int, string, bool> einen Delegat mit zwei Eingabeparametern, int und string, und einem Rückgabetyp von bool. Der folgende Func Delegat gibt beim Aufrufen einen booleschen Wert zurück, der angibt, 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, oder Sie können ihn auch explizit angeben. Dieser spezielle Lambda-Ausdruck zählt die ganzzahligen Zahlen (n), die, wenn sie durch zwei dividiert sind, einen Rest von 1 aufweisen.

Im folgenden Beispiel wird eine Sequenz erzeugt, die alle Elemente im numbers Array enthält, die dem 9 vorausgehen, 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

Im folgenden Beispiel werden mehrere Eingabeparameter angegeben, indem sie in Klammern eingeschlossen werden. Die Methode gibt alle Elemente im numbers Array zurück, bis eine Zahl gefunden wird, deren Wert kleiner als seine Ordnungsposition im Array ist:

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 häufig keinen Typ für die Eingabeparameter angeben, da der Compiler den Typ basierend auf dem Lambda-Textkörper, den Parametertypen und anderen Faktoren ableiten kann, wie in der C#-Sprachspezifikation beschrieben. Bei den meisten standardabfrageoperatoren ist die erste Eingabe der Typ der Elemente in der Quellsequenz. Wenn Sie eine IEnumerable<Customer>abfragen, wird die Eingabevariable als Customer-Objekt abgeleitet, was bedeutet, dass Sie Zugriff auf die zugehörigen Methoden und Eigenschaften haben:

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

Die allgemeinen Regeln für Typinferenz für Lambdas sind 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 Lambda-Ausdruck selbst hat keinen Typ, da das allgemeine Typsystem kein systeminternes Konzept des "Lambda-Ausdrucks" aufweist. Es ist jedoch manchmal praktisch, informell über den "Typ" eines Lambda-Ausdrucks zu sprechen. Dieser informelle „Typ“ bezeichnet den Delegattyp oder den Expression-Typ, in den der Lambdaausdruck konvertiert wird.

Ein Lambdaausdruck kann 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 ableiten, dass parse ein Func<string, int>ist. 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 Lambda-Ausdruck 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 Lambda-Ausdrücke weisen einen natürlichen Typ auf. Berücksichtigen Sie die folgende Erklärung:

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

Der Compiler kann keinen Parametertyp für sableiten. 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

Sie können den Rückgabetyp eines Lambda-Ausdrucks vor den Eingabeparametern angeben. Wenn Sie einen expliziten Rückgabetyp angeben, müssen Sie die Eingabeparameter klammern:

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

Attribute

Sie können einem Lambda-Ausdruck und seinen Parametern Attribute hinzufügen. Das folgende Beispiel zeigt, wie Sie einem Lambda-Ausdruck Attribute hinzufügen:

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

Sie können auch Attribute zu den Eingabeparametern oder rückgabewerten 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 in den vorherigen Beispielen gezeigt, müssen Sie die Eingabeparameter in Klammern setzen, wenn Sie einem Lambda-Ausdruck oder seinen Parametern Attribute hinzufügen.

Wichtig

Lambdaausdrücke werden über den zugrunde liegenden Delegattyp aufgerufen. Das unterscheidet sich von Methoden und lokalen Funktionen. Die Invoke-Methode des Delegaten überprüft keine Attribute für den Lambdaausdruck. Attribute haben keine Auswirkung, wenn der Lambda-Ausdruck aufgerufen wird. Attribute für Lambda-Ausdrücke sind nützlich für die Codeanalyse und können über Spiegelung ermittelt werden. Eine Folge dieser Entscheidung ist, dass die System.Diagnostics.ConditionalAttribute nicht auf einen Lambda-Ausdruck 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. Im folgenden Beispiel werden die folgenden Regeln veranschaulicht:

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 Anmerkungen zu Featurevorschlagen:

Weitere Informationen