Methoden (C#-Programmierhandbuch)
Eine Methode ist ein Codeblock, der eine Reihe von Anweisungen enthält. Ein Programm bewirkt die Ausführung der Anweisungen, indem die Methode aufgerufen wird und alle erforderlichen Methodenargumente angegeben werden. In C# werden alle Anweisungen im Kontext einer Methode ausgeführt.
Die Methode Main
ist der Einstiegspunkt jeder C#-Anwendung und wird beim Start des Programms von der Common Language Runtime (CLR) aufgerufen. In einer Anwendung, die Anweisungen auf oberster Ebene verwendet, wird die Methode Main
vom Compiler generiert und enthält alle Anweisungen auf oberster Ebene.
Hinweis
In diesem Artikel werden benannte Methoden erläutert. Weitere Informationen zu anonymen Funktionen finden Sie unter Lambdaausdrücke.
Methodensignaturen
Methoden werden in einer Klasse, Struktur oder Schnittstelle deklariert, indem die Zugriffsebene wie z. B. public
oder private
, optionale Modifizierer wie z. B. abstract
oder sealed
, der Rückgabewert, der Name der Methode und die Methodenparameter angegeben werden. Diese Teile bilden zusammen die Signatur der Methode.
Wichtig
Ein Rückgabetyp einer Methode ist nicht Teil der Signatur der Methode, wenn es um die Methodenüberladung geht. Er ist jedoch Teil der Methodensignatur, wenn die Kompatibilität zwischen einem Delegaten und der Methode bestimmt wird, auf die dieser verweist.
Methodenparameter werden in Klammern eingeschlossen und durch Kommas getrennt. Leere Klammern geben an, dass für die Methode keine Parameter erforderlich sind. Diese Klasse enthält vier Methoden:
abstract class Motorcycle
{
// Anyone can call this.
public void StartEngine() {/* Method statements here */ }
// Only derived classes can call this.
protected void AddGas(int gallons) { /* Method statements here */ }
// Derived classes can override the base class implementation.
public virtual int Drive(int miles, int speed) { /* Method statements here */ return 1; }
// Derived classes must implement this.
public abstract double GetTopSpeed();
}
Methodenzugriff
Das Aufrufen einer Methode für ein Objekt ähnelt dem Zugreifen auf ein Feld. Fügen Sie nach dem Objektnamen einen Punkt, den Namen der Methode und Klammern hinzu. Argumente werden innerhalb der Klammern aufgelistet und durch Kommas getrennt. Die Methoden der Motorcycle
-Klasse können also wie im folgenden Beispiel gezeigt aufgerufen werden:
class TestMotorcycle : Motorcycle
{
public override double GetTopSpeed()
{
return 108.4;
}
static void Main()
{
TestMotorcycle moto = new TestMotorcycle();
moto.StartEngine();
moto.AddGas(15);
moto.Drive(5, 20);
double speed = moto.GetTopSpeed();
Console.WriteLine("My top speed is {0}", speed);
}
}
Methodenparameter und Argumente
Die Methodendefinition gibt die Namen und Typen aller ggf. erforderlichen Parameter an. Wenn aufrufender Code die Methode aufruft, werden für jeden Parameter konkrete Werte bereitgestellt, die als Argumente bezeichnet werden. Die Argumente müssen mit dem Parametertyp kompatibel sein, aber der im aufrufenden Code verwendete Name des Arguments (sofern vorhanden) muss nicht mit dem in der Methode definierten Parameternamen identisch sein. Zum Beispiel:
public void Caller()
{
int numA = 4;
// Call with an int variable.
int productA = Square(numA);
int numB = 32;
// Call with another int variable.
int productB = Square(numB);
// Call with an integer literal.
int productC = Square(12);
// Call with an expression that evaluates to int.
productC = Square(productA * 3);
}
int Square(int i)
{
// Store input argument in a local variable.
int input = i;
return input * input;
}
Übergeben nach Verweis und Übergeben nach Wert
Wenn eine Instanz eines Werttyps an eine Methode übergeben wird, wird standardmäßig die zugehörige Kopie anstelle der Instanz selbst übermittelt. Änderungen am Argument haben daher keine Auswirkungen auf die originale Instanz in der aufrufenden Methode. Verwenden Sie das Schlüsselwort ref
, um eine Werttypinstanz als Verweis zu übergeben. Weitere Informationen finden Sie unter Übergeben von Werttypparametern.
Wenn ein Objekt eines Verweistyps an eine Methode übergeben wird, wird ein Verweis auf das Objekt übergeben. Das heißt, die Methode erhält nicht das Objekt selbst, sondern ein Argument, das den Speicherort des Objekts angibt. Wenn Sie einen Member des Objekts unter Verwendung dieses Verweises ändern, wird die Änderung im Argument in der aufrufenden Methode berücksichtigt, selbst wenn Sie das Objekt als Wert übergeben.
Sie erstellen einen Verweistyp mithilfe des class
-Schlüsselworts, wie im folgenden Beispiel gezeigt:
public class SampleRefType
{
public int value;
}
Wenn Sie jetzt ein Objekt, das auf diesem Typ basiert, an eine Methode übergeben, wird ein Verweis auf das Objekt übergeben. Das folgende Beispiel übergibt ein Objekt des SampleRefType
-Typs an die ModifyObject
-Methode:
public static void TestRefType()
{
SampleRefType rt = new SampleRefType();
rt.value = 44;
ModifyObject(rt);
Console.WriteLine(rt.value);
}
static void ModifyObject(SampleRefType obj)
{
obj.value = 33;
}
Das Beispiel entspricht im Wesentlichen dem vorherigen Beispiel und übergibt ein Argument als Wert an eine Methode. Aber da ein Verweistyp verwendet wird, unterscheidet sich das Ergebnis. Die Änderung, die in ModifyObject
am value
-Feld des Parameters ( obj
) vorgenommen wird, ändert auch das value
-Feld des Arguments ( rt
) in der TestRefType
-Methode. Die TestRefType
-Methode zeigt 33 als Ausgabe an.
Weitere Informationen zum Übergeben von Verweistypen als Verweis oder als Wert finden Sie unter Übergeben von Verweistypparametern und Verweistypen.
Rückgabewerte
Methoden können einen Wert an die aufrufende Funktion (den Aufrufer) zurückgeben. Wenn der Rückgabetyp (der vor dem Methodennamen aufgeführte Typ) nicht void
ist, kann die Methode den Wert mithilfe der return
-Anweisung zurückgeben. Eine Anweisung mit der return
-Schlüsselwort, gefolgt von einem Wert, der dem Rückgabetyp entspricht, gibt diesen Wert an den Methodenaufrufer zurück.
Der Wert kann an den Aufrufer nach Wert oder nach Verweis zurückgegeben werden. Werte werden an den Aufrufer nach Verweis zurückgegeben, wenn das Schlüsselwort ref
in der Methodensignatur verwendet wird und auf jedes return
-Schlüsselwort folgt. Die folgende Methodensignatur und Rückgabeanweisung geben an, dass die Methode eine Variable mit dem Namen estDistance
nach Verweis an den Aufrufer zurückgibt.
public ref double GetEstimatedDistance()
{
return ref estDistance;
}
Das return
-Schlüsselwort beendet außerdem die Ausführung der Methode. Wenn der Rückgabetyp void
ist, ist eine return
-Anweisung ohne Wert immer noch nützlich, um die Ausführung der Methode zu beenden. Ohne das return
-Schlüsselwort wird die Ausführung der Methode beendet, wenn das Ende des Codeblocks erreicht ist. Methoden mit einem anderen Rückgabetyp als „void“ müssen das return
-Schlüsselwort verwenden, um einen Wert zurückzugeben. Die folgenden beiden Methoden verwenden z. B. das return
-Schlüsselwort, um ganze Zahlen zurückzugeben:
class SimpleMath
{
public int AddTwoNumbers(int number1, int number2)
{
return number1 + number2;
}
public int SquareANumber(int number)
{
return number * number;
}
}
Um einen von einer Methode zurückgegebenen Wert zu verwenden, kann die aufrufende Methode den Methodenaufruf selbst an jeder Stelle verwenden, an der ein Wert des gleichen Typs ausreichend ist. Sie können den Rückgabewert auch einer Variablen zuweisen. Beispielsweise wird mit den folgenden beiden Codebeispiele das gleiche Ergebnis erzielt:
int result = obj.AddTwoNumbers(1, 2);
result = obj.SquareANumber(result);
// The result is 9.
Console.WriteLine(result);
result = obj.SquareANumber(obj.AddTwoNumbers(1, 2));
// The result is 9.
Console.WriteLine(result);
Die Verwendung einer lokalen Variablen, in diesem Fall result
, zum Speichern eines Werts ist optional. Es kann die Lesbarkeit des Codes verbessern, oder es kann notwendig sein, wenn Sie den ursprünglichen Wert des Arguments für den gesamten Gültigkeitsbereich der Methode speichern müssen.
Um einen Wert zu verwenden, der nach Verweis von einer Methode zurückgegeben wurde, müssen Sie die Variable ref local deklarieren, wenn Sie diesen Wert modifizieren möchten. Wenn die Planet.GetEstimatedDistance
-Methode z.B. einen Double-Wert nach Verweis zurückgibt, können Sie ihn mit Code wie dem folgenden als ref local-Variable definieren:
ref double distance = ref Planet.GetEstimatedDistance();
Die Zurückgabe eines mehrdimensionalen Arrays aus einer Methode, M
, die den Inhalt eines Arrays modifiziert, ist nicht vonnöten, wenn die aufrufende Funktion das Array an M
übergeben hat. Sie können das resultierende Array aus M
für den funktionalen Fluss der Werte oder aus stilistischen Gründen zurückgeben. Dies ist jedoch nicht nötig, da C# alle Referenztypen nach Wert übergibt und der Wert eines Arrayverweises ein Zeiger auf das Array ist. In der Methode M
werden Änderungen am Inhalt des Arrays durch jeden Code berücksichtigt, der einen Verweis auf das Array enthält, wie im folgenden Beispiel gezeigt:
static void Main(string[] args)
{
int[,] matrix = new int[2, 2];
FillMatrix(matrix);
// matrix is now full of -1
}
public static void FillMatrix(int[,] matrix)
{
for (int i = 0; i < matrix.GetLength(0); i++)
{
for (int j = 0; j < matrix.GetLength(1); j++)
{
matrix[i, j] = -1;
}
}
}
Asynchrone Methoden
Mithilfe der Async-Funktion können Sie asynchrone Methoden aufrufen, ohne explizite Rückrufe verwenden oder den Code manuell über mehrere Methoden oder Lambda-Ausdrücke teilen zu müssen.
Wenn Sie eine Methode mit dem Modifizierer async kennzeichnen, können Sie den Operator await in der Methode verwenden. Wenn ein await-Ausdruck in der asynchronen Methode erreicht wird, wird die Steuerung an den Aufrufer zurückgegeben, und die Ausführung der Methode wird angehalten, bis die erwartete Aufgabe abgeschlossen ist. Wenn die Aufgabe abgeschlossen ist, kann die Ausführung in der Methode fortgesetzt werden.
Hinweis
Eine asynchrone Methode wird an den Aufrufer zurückgegeben, wenn sie entweder auf das erste erwartete Objekt trifft, das noch nicht abgeschlossen wurde, oder das Ende der asynchronen Methode erreicht.
Eine asynchrone Methode weist üblicherweise den Rückgabetyp Task<TResult>, Task, IAsyncEnumerable<T> oder void
auf. Der Rückgabetyp void
wird hauptsächlich zum Definieren von Ereignishandlern verwendet, wobei ein void
-Rückgabetyp erforderlich ist. Auf eine asynchrone Methode, die void
zurückgibt, kann nicht gewartet werden, und der Aufrufer einer Methode mit void-Rückgabe kann keine Ausnahmen abfangen, die die Methode auslöst. Eine asynchrone Methode kann jeden taskähnlichen Typ zurückgeben.
Im folgenden Beispiel ist DelayAsync
eine asynchrone Methode mit dem Rückgabetyp Task<TResult>. DelayAsync
enthält eine return
-Anweisung, die eine ganze Zahl zurückgibt. Aus diesem Grund muss die Methodendeklaration von DelayAsync
den Rückgabetyp Task<int>
haben. Da der Rückgabetyp Task<int>
ist, ergibt die Auswertung des await
-Ausdrucks in DoSomethingAsync
eine ganze Zahl, wie die folgende Anweisung veranschaulicht: int result = await delayTask
.
Die Main
-Methode ist ein Beispiel für eine asynchrone Methode mit dem Task-Rückgabetyp. Es folgt die DoSomethingAsync
-Methode, und da sie mit einer einzelnen Zeile ausgedrückt wird, können Sie die Schlüsselwörter async
und await
weglassen. Da DoSomethingAsync
eine asynchrone Methode ist, muss die Aufgabe für den Aufruf von DoSomethingAsync
abgewartet werden, wie in der folgenden Anweisung dargestellt: await DoSomethingAsync();
.
class Program
{
static Task Main() => DoSomethingAsync();
static async Task DoSomethingAsync()
{
Task<int> delayTask = DelayAsync();
int result = await delayTask;
// The previous two statements may be combined into
// the following statement.
//int result = await DelayAsync();
Console.WriteLine($"Result: {result}");
}
static async Task<int> DelayAsync()
{
await Task.Delay(100);
return 5;
}
}
// Example output:
// Result: 5
Mit einer asynchronen Methode können keine ref - oder out -Parameter deklariert, jedoch Methoden aufgerufen werden, die solche Parameter aufweisen.
Weitere Informationen zu den asynchronen Methoden finden Sie unter Asynchrone Programmierung mit async und await und Asynchrone Rückgabetypen (C#).
Ausdruckstextdefinitionen
Es gibt häufig Methodendefinitionen, die einfach direkt das Ergebnis eines Ausdrucks zurückgeben oder eine einzige Anweisung als Text der Methode aufweisen. Es ist eine Syntaxabkürzung zur Definition solcher Methoden mithilfe von =>
verfügbar:
public Point Move(int dx, int dy) => new Point(x + dx, y + dy);
public void Print() => Console.WriteLine(First + " " + Last);
// Works with operators, properties, and indexers too.
public static Complex operator +(Complex a, Complex b) => a.Add(b);
public string Name => First + " " + Last;
public Customer this[long id] => store.LookupCustomer(id);
Wenn die Methode void
zurückgibt oder es sich um eine asynchrone Methode handelt, muss der Text der Methode ein Anweisungsausdruck sein (wie bei Lambdas). Eigenschaften und Indexer müssen schreibgeschützt sein. Verwenden Sie darüber hinaus nicht das get
-Accessorschlüsselwort.
Iterators
Ein Iterator führt eine benutzerdefinierte Iteration durch eine Auflistung durch, z. B. eine Liste oder ein Array. Ein Iterator verwendet die yield return -Anweisung, um jedes Element einzeln nacheinander zurückzugeben. Wenn eine yield return
-Anweisung erreicht wird, wird die aktuelle Position im Code gespeichert. Wenn der Iterator das nächste Mal aufgerufen wird, wird die Ausführung von dieser Position neu gestartet.
Sie rufen einen Iterator im Clientcode mithilfe einer foreach Anweisung auf.
Der Rückgabetyp eines Iterators kann IEnumerable, IEnumerable<T>, IAsyncEnumerable<T>, IEnumerator oder IEnumerator<T> sein.
Weitere Informationen finden Sie unter Iteratoren.
C#-Sprachspezifikation
Weitere Informationen erhalten Sie unter C#-Sprachspezifikation. Die Sprachspezifikation ist die verbindliche Quelle für die Syntax und Verwendung von C#.