This article is currently in the process of being translated into German (~99% done).
Local functions
In früheren Artikeln haben wir gelernt, dass Methoden und Eigenschaften zu Klassen in C# gehören. Innerhalb von Methoden können Sie lokale Variablen haben, d.h. Variablen, auf die nur im Rahmen dieser speziellen Methode zugegriffen werden kann. Dies ist sinnvoll, da Sie oft temporäre Daten haben werden, die Sie speichern müssen, auf die aber von anderen Klassen oder sogar anderen Methoden in derselben Klasse nicht zugegriffen werden sollte. Früher konnte man nicht dasselbe mit Methoden machen - wenn eine Methode in einer Klasse deklariert war, konnte zumindest von anderen Methoden innerhalb derselben Klasse darauf zugegriffen werden, bis in C# Version 7 das Konzept der lokalen Funktionen eingeführt wurde.
Eine lokale Funktion wird innerhalb einer bestehenden Methode deklariert und kann nur von dieser Methode aus aufgerufen werden. Dies kapselt Funktionalität sehr eng und macht auch allen Lesern Ihres Codes klar, dass diese Funktionalität nur für die deklarierende Methode relevant ist. Eine lokale Funktion sieht wie eine reguläre Methode aus, jedoch ohne den Sichtbarkeitsmodifikator, weil auf eine lokale Funktion immer nur innerhalb der deklarierenden Methode zugegriffen werden kann. Hier ist ein Beispiel:
public void MethodWithLocalFunction()
{
bool doesNameStartWithUppercaseChar(string name)
{
if(String.IsNullOrEmpty(name))
throw new Exception("name parameter must contain a value!");
return Char.IsUpper(name[0]);
}
List<string> names = new List<string>()
{
"john doe",
"Jane doe",
"dog Doe"
};
foreach(string name in names)
Console.WriteLine(name + " starts with uppercase char: " + doesNameStartWithUppercaseChar(name));
}
Ein ziemlich albernes Beispiel, aber es zeigt, wie Sie eine lokale Funktion (in diesem Fall doesNameStartWithUppercaseChar) innerhalb einer Methode (MethodWithLocalFunction) deklarieren und sie dann ein oder mehrere Male von innerhalb dieser einen speziellen Methode aufrufen können.
Wie Sie in meinem Beispiel sehen können, deklariere ich die lokale Funktion am Anfang der Methode. Es steht Ihnen frei, dies zu ändern, z.B. indem Sie sie in der Mitte oder am Ende der Methode deklarieren. Nur in einem Fall wird es einen Unterschied machen: Eine lokale Funktion darf auf Variablen zugreifen, die innerhalb der deklarierenden Methode deklariert sind, aber nur, wenn sie vor der lokalen Funktion deklariert wurden. Wenn Sie also dieses Verhalten ausnutzen wollen, müssen Sie die Methode modifizieren, z.B. so:
public void MethodWithLocalFunction()
{
int nameMaxLength = 10;
List<string> names = new List<string>()
{
"john doe",
"Jane doe",
"dog Doe"
};
foreach(string name in names)
Console.WriteLine(name + " starts with uppercase char: " + doesNameStartWithUppercaseChar(name));
bool doesNameStartWithUppercaseChar(string name)
{
if(String.IsNullOrEmpty(name))
throw new Exception("name parameter must contain a value!");
if(name.Length > nameMaxLength)
throw new Exception("name is too long! Max length: " + nameMaxLength);
return Char.IsUpper(name[0]);
}
}
Beachten Sie, wie ich die Variable nameMaxLength innerhalb der Methode deklariere und dann innerhalb der lokalen Funktion darauf zugreife.
Statische lokale Funktionen
In C# Version 8 wurde die Unterstützung für statische lokale Funktionen hinzugefügt. Zum Zeitpunkt des Schreibens besteht der einzige Unterschied zwischen einer regulären und einer statischen lokalen Funktion darin, dass eine statische lokale Funktion keine Variablen aus der Deklarationsmethode verwenden kann - mit anderen Worten, sie teilen sich nicht mehr den Anwendungsbereich. Wenn Sie also sicherstellen wollen, dass Ihre lokale Funktion keine Variablen aus der Methode referenzieren oder ändern kann, deklarieren Sie sie einfach wie folgt als statisch:
public void MethodWithLocalStaticFunction()
{
int nameMaxLength = 10;
static bool doesNameStartWithUppercaseChar(string name)
{
// Local variables, e.g. nameMaxLength, are no longer accessible here....
if(String.IsNullOrEmpty(name))
throw new Exception("name parameter must contain a value!");
return Char.IsUpper(name[0]);
}
....
}
Zusammenfassung
In manchen Situationen können lokale Funktionen tolle kleine Hilfen sein wenn es darum geht, ganz bestimmte Funktionen zu kapseln und wiederzuverwenden. Als Alternative, wenn die Funktionalität von anderen Methoden wiederverwendet werden kann oder soll, sollten Sie in Erwägung ziehen, sie als echte Methode in eine Helferklasse oder als Erweiterungsmethode einzufügen.